A Kendo Template With DropDownList inside Form Louyot Genrate Ivald Template when setting ServerFiltering to True - asp.net-core

When creating kendo ui Javascript template and using a form layout, adding a DropDownList with server filtering set to true , kendo ui will throw an "invalid template " error.
While setting the server filtering to false it will work as expected
Sample code
https://github.com/Elrashid/TelerikAspNetCoreApp.tiket.2022121901
compiled code
https://github.com/Elrashid/TelerikAspNetCoreApp.tiket.2022121901/releases/download/202211219194020/publish-self-contaned.zip
Tested Scenarios:
✔DropDownList with ServerFiltering trueinside Kendo Tempate will work
✔DropDownList with ServerFiltering false will was a Form Layout Editer inside Kendo Tempate will work
❌DropDownList with ServerFiltering true will was a Form Layout Editer inside Kendo Tempate will not work
Error :
[](https://i.stac> k.imgur.com/nULHE.png)
Error Code :
#(Html.Kendo().Form()
.Name("Biblio_Form")
.HtmlAttributes(new { action = "Biblio_Save", method = "POST", })
.Layout("grid")
.Grid(g => g.Cols(1).Gutter(10))
.Validatable(v =>
{
v.ValidateOnBlur(true);
v.ValidationSummary(vs => vs.Enable(false));
})
.Items(items =>
{
items.Add()
.Field(f => f.BiblioId)
.Label(l => l.Text("Biblio Id"))
.Editor(e =>
{
e.DropDownList()
.HtmlAttributes(new { })
.DataTextField("Title")
.DataValueField("BiblioId")
.NoDataTemplate("nodata")
.Filter(FilterType.Contains)
.DataSource(source =>
{
source.Read(read =>
{
read.Action("biblio_read", "Home");
})
.ServerFiltering(true);
});
});
}).ToClientTemplate())

Explicitly call the .ToClientTemplate() configuration method.
Addunique identifier thru .Name() configuration option.
this will have to be doen even if you call.ToClientTemplate() on the parent , so you have to call it for the children also
<script type="text/x-kendo-template" id="...........">
#(Html.Kendo().Form<Biblio>()
.Name("Biblio_Form")
....
.Items(items =>
{
items.Add()
.Field(f => f.BiblioId)
.Label(l => l.Text("Biblio Id"))
.Editor(e =>
{
e.DropDownList()
.Name("serverFilteringTrue")
.DataTextField("Title")
.DataValueField("BiblioId")
.Filter(FilterType.Contains)
.DataSource(source =>
{
source.Read(read =>
{
read.Action("biblio_read", "Home");
})
.ServerFiltering(true);
}).ToClientTemplate();
});
}).ToClientTemplate())
</script>
Ref.
[ASP.NET Core Data Grid Component Client Detail Templates - Telerik UI for ASP.NET Core]
(https://docs.telerik.com/aspnet-core/html-helpers/data-management/grid/templates/client-detail-template)

Related

How can I access to each element inside of a grid element with Cypress?

I have a Grid component which includes 24 divs and inside of each div I need to take the value.
This value actually arrives in <p>, so which is the best way to do this?
Below is the app image. I would appreciate an example.
You could probably do something like storing the data in an object or array outside of the Cypress chain. Without a code example, here's my best guess.
cy.get('grid').within(() => { // cy.within() searches only within yielded element
const data = {}; // create data object
cy.get('div').each(($div, index) => { // cy.each() allows us to iterate through yielded elements
data[index] = $div.text() // or possibly some other JQuery command to get the value
// additionally, could go without the index at all and make `data` an array.
}).then(() => {
// whatever needs to be done with `data`, wrapped in `then` to make sure data is populated correctly.
});
});
You can add use each for this to loop through the elements and then do further operations:
cy.get('.chakra-stack')
.find('p')
.each(($ele) => {
cy.log($ele.text().trim()) //Logs all the texts one by one
})
Just add the p selector to your cy.get() command
cy.get('div.chakra-stack p') // access <p> within <div>
.each($el => {
cy.wrap($el).invoke('text')
.then(text => {
...
})
})
To get the value before the text
cy.get('div.chakra-stack p') // access <p> within <div>
.each($el => {
cy.wrap($el)
.prev() // element with value
.invoke('text')
.then(value => {
...
})
})
Accessing values by text label like this
const values = {}
cy.get('div.chakra-stack p')
.each($el => {
const frase = $el.text()
cy.wrap($el).prev().invoke('text')
.then(value => values[frase] = +value)
})
.then(() => {
// values = {'shield': 1, 'session': 2, ...}
})

vuejs dynamically adding class

Using vuejs 3. In the vuejs app, I have:
data(){
return{
return_prohibited:false
}
}
return_prohibited turns to true when the server returns an error message from a fetch request:
fetch(myUrl,this.myInit)
.then(response => response.json())
.then(data => {
if (data.message) {
this.credits = []
this.debits = []
return_prohibited = true
} // cut for brievity
Html file:
<button #click="previousMonth" id="bouton_mois_prec" :class="{interdit:return_prohibited}" >précédent</button>
I was expecting that the css class interdit would be added to the button each time that return_probibited is true, as per these explanations. But nothing happens.
You should append this. in front of return_prohibited - otherwise you will get errors in the console.

How to solve Validation error after submit

I use veevalidate rule for each input in my form. After submit with valid data, all these data have been sent successfully to backend-side, but on frontend-side each input is highlighted as it ivalid.
I had added reset method from veevalidate to unset any errors when submit is selected. But it don't work. Here is the part of my code
beforeSubmit() {
this.$validator.pause();
this.$nextTick(() => {
this.$validator.errors.clear();
this.$validator.fields.items.forEach(field =>
field.reset());
this.$validator.fields.items.forEach(field =>
this.errors.remove(field));
this.$validator.resume();
});
this.$validator.validateAll().then((result) => {
this.onSubmit();
...
I came to solution: when all errors have been removed from the form in next render with $nextTick, we should replace this.$validator.resume() method with this.$validator.reset(). Thant's it.
In general, the working part is
beforeSubmit() {
this.$validator.pause();
this.$nextTick(() => {
this.$validator.errors.clear();
this.$validator.fields.items.forEach(field =>
field.reset());
this.$validator.fields.items.forEach(field =>
this.errors.remove(field));
this.$validator.reset();
});
this.$validator.validateAll().then((result) => {
this.onSubmit();
...

cypress custom find command

I have a custom command that gets me my elements with the data-cy attribute.
Cypress.Commands.add("getById", (id) => {
cy.get(`[data-cy=${id}]`)
})
everything's working fine.
Now it would be nice if I had the same with find. It would be looking like this:
Cypress.Commands.add("findById", { prevSubject: true }, (subject, id) => {
cy.wrap(subject).find(`[data-cy=${id}]`)
})
The problem there is that cypress throws an error with this code:
cy.root().then((root) => {
if(root.findById("...").length) {
...
}
})
The error is "root.findById" is not a function.
Can you help me write that custom command correctly?
The basic problem is that subject passed in to the command is already wrapped, so just chain the find() from it. Also you need to return the result to use it in the test.
Custom command
Cypress.Commands.add("findById", { prevSubject: true }, (subject, id) => {
return subject.find(`[data-cy=${id}]`)
})
The next problem is you can't mix 'ordinary' js code with Cypress commands, so the returned value must be accessed from a .then().
Spec
describe('...', () => {
it('...', () => {
cy.visit('app/find-by-id.html')
cy.root().findById('2').then(el => {
console.log('found', el, el.length)
expect(el.length).to.eq(2)
})
})
})
Html used to test the test (app/find-by-id.html)
<div>
<div data-cy="1"></div>
<div data-cy="2"></div>
<div data-cy="2"></div>
<div data-cy="3"></div>
</div>
Adding to #Richard Matsen's answer, you might want to add some log into your command, so that it appears well in your cypress log, just as if you had used .find(...) directly:
Cypress.Commands.add(
"findByTestId",
{
prevSubject: ["element"],
},
(
subject: Cypress.Chainable<HTMLElement>,
testId: string,
options?: Partial<
Cypress.Loggable &
Cypress.Timeoutable &
Cypress.Withinable &
Cypress.Shadow
>
) => {
const $el = subject.find(`[data-testid=${testId}]`, options);
Cypress.log({
$el: $el as any,
name: "findByTestId",
message: testId,
});
return $el;
}
);

Download pdf files from kendo ui grid

I have a table column called PDF(varbinary). The column will bind in kendo ui grid as hyperlink which download the pdf from the database.
The following is the code that i have so far. Based on the research i have done. Therefore i am implementing a template.
The italic code below showing said error "required )" and i am not quite sure what i am missing here.
columns.Template(#).ClientTemplate("Download file").Title("Download1");
Therefore I would kindly advise to implement the download file (pdf format) in kendo ui grid. Thank you
#(Html.Kendo().Grid<HH.Models.OrderModel>()
.Name("OrderGrid")
.HtmlAttributes(new { #Style = "align:center; font-size:10px; width:600px" })
.Columns(columns =>
{
columns.Bound(p => p.OrderId);
columns.Bound(p => p.Date).EditorTemplateName("Date").Format("{0:dd/MM/yyyy}");
columns.Bound(p => p.CustFullName).Width(120);
columns.Template(#<text></text>).ClientTemplate("Download file").Title("Download1");
columns.Template(#<text></text>).ClientTemplate("" + Html.ActionLink("<img src='" + Url.Content("~/Content/icons/pdficon_small.png") + "' />", "DocumentDownload2", "Administration", new { id = "#=OrderId#" }, null) + "").Title("Download2");
})
.ToolBar(toolbar => toolbar.Save().Text("Save Changes"))
.Editable(editable => editable.Mode(GridEditMode.InCell))
.Selectable()
.Pageable(paging => paging
.Input(false)
.Numeric(true)
.PreviousNext(true)
.PageSizes(new int[] { 5, 10, 25, 50 })
.Refresh(false)
)
.DataSource(dataSource => dataSource
.Ajax()//bind with Ajax instead server bind
.PageSize(10)
.ServerOperation(true)
.Model(model =>
{
model.Id(p => p.OrderId);
})
.Read(read => read.Action("GetOrder", "Administration").Type(HttpVerbs.Get))
.Update("EditOrder", "Administration")
)
)
**controller**
public ActionResult Download1()
{
string contentType = "application/pdf";
string filePath = Server.MapPath("~/Files/OrderDetails.pdf");
return File(filePath, contentType, "OrderDetails.pdf");
}
public ActionResult Download2(int orderId)
{
string contentType = "application/xlsx";
string filePath = Server.MapPath("~/Files/OrderDetails.pdf");
return File(filePath, contentType, "OrderDetails.pdf_" + orderId.ToString() + ".xlsx");
}
You can't implement the PDF download on the client-side easily. You should instead stream the PDF file using another action method. You can check this question for some ideas: Retrieve and display image from database using ASP.Net MVC
The grid should contain a link to this action method:
.ClientTemplate("<a href='/administration/getpdf?orderid=#= OrderID #'>get pdf</a>");
public ActionResult GetPdf(int orderID)
{
// find the pdf by orderid
return File(stream, "application/pdf", "DownloadName.pdf");
}
You'd have to implement this yourself. KendoUI is a client-side technology, and has nothing to do with serving an arbitary PDF from a datasource.
If you'd like to generate a PDF, look up the following resources:
PDF:
http://www.kendoui.com/code-library/mvc/grid/export-grid-to-pdf.aspx
Maybe this UserVoice entry:
http://feedback.kendoui.com/forums/127393-kendo-ui-feedback/suggestions/3494585-kendoui-mvc-serverside-wrappers-should-allow-expor
The available answers seem to be outdated. There are new developments in this area. Please check this example and also telerik api reference . Hope it helps in the future.
Another way to do the same thing, with ActionLink inside the ClientTemplate:
columns.Template(#<text>
#Html.ActionLink("get pdf", "getpdf", "administration", new { orderid= #item.OrderId}, null)
</text>);
As taken from: http://docs.telerik.com/kendo-ui/aspnet-mvc/helpers/grid/faq#how-do-i-use-action-links