And Read, Create, Update, Destroy works fine when working with only one row at a time.
But, when i try to add two Customer's the EditingPopup_Create is called three times. One for the first row, and two for the second row... If i add more than two rows the same pattern follows. The EditingPopup_Create method is run as many times as the count of it's customer....
Current implementation is like this:
#(Html.Kendo().Grid<CustomerModel>()
.Name("grid")
.Columns(columns =>
{
columns.Bound(p => p.Name);
columns.Bound(p => p.ContactPerson);
columns.Bound(p => p.ContactPersonEmail);
columns.Bound(p => p.ContactPersonPhone);
columns.Bound(p => p.MainPhoneNumber);
columns.Command(command => { command.Edit(); command.Destroy(); }).Width(180);
})
.ToolBar(toolbar => toolbar.Create())
.Editable(editable => editable.Mode(GridEditMode.PopUp).TemplateName("CustomerPopUpTemplate"))
.Pageable()
.Sortable()
.Scrollable()
.HtmlAttributes(new {style = "height:500px;"})
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(10)
//.Events(events => events.Error("error_handler"))
.Model(model => model.Id(p => p.Id))
.Read(read => read.Action("EditingPopup_Read", "CustomerManagement"))
.Create(update => update.Action("EditingPopup_Create", "CustomerManagement"))
.Update(update => update.Action("EditingPopup_Update", "CustomerManagement"))
.Destroy(destroy => destroy.Action("EditingPopup_Destroy", "CustomerManagement"))
)
)
This is probably a newbie mistake, but i cant seem to figure out why this would happen. In my opinion the wiring of the grid should only call the methods once per instance.
Explanation would be greatly appreciated :)
When you perform the save on create are you changing the id associated with the item created?
I suspect what you are doing is not changing the id from what is being provided and grid treats this as another create.
So when you are saving your item back to the database set the id to the database generated or how ever you are generating it and you should see it not doing the second call.
Showing the controller code will help as well to answer it.
Make sure you are returning the model back to the view so that it updates the id associated with it via the json.
Eg
Return json( new { model }.todatasourceresult(request, modelState))
Found a post that answered my question and filled out the question a bit more too...
Kendo UI Grid posting back already Inserted Rows again
A way of explaining it is that if the Id of an object is 0 the grid thinks it's a new row. If it's a new row it thinks it has to insert it. If the value of the Object/Row in the grid is not updated when the row is added, it will try to re-add it because it thinks it does not exist.
I hope this could help anyone out there... :)
Related
I've just started using Telerik, to speed up some of my development, however I'm stuck trying to bring up a normal MVC Details page from a Grid Component.
All I want, is a select button to send the user to something like /Person/Details/5
The reason why I want a separate page (rather than a popup) is that some of the data relationships are complex, and it's better experience that these are displayed in it's own page, rather than a popup.
My model has a few objects, that's why you see the p.person.Title type setup below.
#(Html.Kendo().Grid(Model)
.Name("grid")
.Columns(columns =>
{
columns.Bound(p => p.person.Title).Width(100);
columns.Bound(p => p.person.Firstname);
columns.Bound(p => p.person.Firstname);
columns.Bound(p => p.person.Surname);
columns.Bound(p => p.person.ABN).Width(210);
columns.Bound(p => p.person.PracticeCode);
columns.Bound(p => p.currentform);
columns.Command(command => { command.Edit(); });
columns.Command(command => { command.Destroy(); });
columns.Command(command => { command.Select(); });
})
.Sortable()
.ToolBar(commands => commands.Create())
.Editable(editable => editable.Mode(GridEditMode.PopUp))
.DataSource(dataSource => dataSource
.Server()
.Model(model => model.Id(p => p.person.personkey))
.Create(create => create.Action("Create", "Person"))
.Read(read => read.Action("Details", "Person" ))
.Update(update => update.Action("Update", "Person"))
.Destroy(destroy => destroy.Action("Destroy", "Person"))
The grid itself is working fine, however, when someone selects the "Select" button, I want them to go to the /Person/Details/{id} page. Telerik is almost doing it right, it's sending the user to
/Person/Details?grid-mode=select&person.personkey=11 (I actually want /Person/Details/11 )
So, I noticed that the "Read" method has a few different signatures to enable route values, but I just can't seem to rig it up to get the right route values.
I've tried....
.Read(read => read.Action("Details", "Practitioner", p => p.practitioner.drkey ))
and combinations of, but I just can't seem to get the right route value in there.
How do I correctly specify the right route values ?
I ended by solving this with a Template.
Not exactly the outcome I was looking for, but close enough at this stage.
columns.Bound(p => p.person.pkey).Template(#<text>
#Html.ActionLink("Details" , "Details" , new { id = #item.person.pkey })
</text>);
The trick is that a traditional MVC razor action is placed inside a Telerik Template.
It also removed the need for the .Select and .Read rows.
I am using Kendo Gridview to display some records. These records are in Json when retrieved from the database and stored in a list of the same class. I have no problem when the list is of count 1000, but any number above 1000 triggers an exception : "Error during serialization or deserialization using the JSON JavaScriptSerializer. The length of the string exceeds the value set on the maxJsonLength property."
I have tried changing the maxJsonLength value in web.config and in appsettings as recommended in some of the solutions I found on stack overflow. But none of them work. This is my view:
#(Html.Kendo().Grid(Model)
.Name("grid")
.Scrollable()
.Filterable()
.Columns(columns =>
{
//Columns added here
})
.Selectable(selectable => selectable.Mode(GridSelectionMode.Single))
.Pageable(pageable => pageable
.Refresh(false)
.PageSizes(true)
.ButtonCount(3))
.DataSource(dataSource => dataSource
.Ajax()
.ServerOperation(false)
.Model(model =>
{
model.Id(p => p.Id);
model.Field(p => p.Id).Editable(false);
})
.Read(read => read.Action("Action", "Controller"))
.PageSize(50)
)
.Events(e => e.DataBound("selectDefault"))
I came to realize that the Json Lists that I was passing to the view had too many complex data types(i.e class objects and enums) and that was the reason none of the solutions worked. So I referred to a solution described in this link and created an intermediate view model. In this model I added all the necessary attributes that I wanted and passed it to view. It works really fine now
Here is my issue :
I have two project with similar code to display a dropdownlist inside a kendogrid. In the first project all works fine, in the second project i got a textbox dipslaying instead of a dropdown. I've searched around telerik but nothing could resolve my issue. I think something is missing in my project to make this work fine. Or something is blocking it ! But can't find .. Hope you could help me !
Here is my grid :
#(Html.Kendo().Grid<DisplayUniteMultiple>()
.Name("GridDisplayUniteMultiple")
.ToolBar(t => t.Create().Text("Ajouter un couple Valeur/ Unite"))
.Columns(columns =>
{
columns.Bound(c => c.id).Hidden(true);
columns.Bound(c => c.Valeur);
columns.ForeignKey(c => c.Unite, unitesDeConversion, "Value", "Text").Title("Unité").Width(200);
})
.Editable(editable => editable.Mode(GridEditMode.InCell).Enabled(true))
.Events(e => e.Edit("onGridChange"))
.DataSource(datasource => datasource
.Ajax()
.Update(builder => builder.Url(""))
.PageSize(50)
.Batch(false)
.Model(model =>
{
model.Id(uniteMultiple => uniteMultiple.id);
model.Field(uniteMultiple => uniteMultiple.Valeur);
model.Field(uniteMultiple => uniteMultiple.Unite);
})
.ServerOperation(true)
))
You might missing to add the editor template in your project.
Create a new folder named EditorTemplates in ../Views/Shared/ directory, if there is not already. Then create new file named GridForeignKey.cshtml in that folder and copy below code into it, save and try again.
#model object
#(
Html.Kendo().DropDownListFor(m => m)
.BindTo((SelectList)ViewData[ViewData.TemplateInfo.GetFullHtmlFieldName("") + "_Data"])
)
My project has two main issues that prevent me from being able to do a normal, basic Kendo UI gridbind. 1. I do not have full access to the required SQL data (I cannot create a view) 2. One of the fields is incredibly large (the field overloads a ViewModel).
I was able to get my grid to work, but I feel that there is a better way to accomplish the task. My problem, essentially, is that I can only seem to gridbind to a single table of DB. To get passed this, I bound to the foreign key field and used a clientTemplate to fill the data from the read, but I feel like there should be a more direct way to be able to bind the field to the data. My read data is an actionresult Linq join from EF, converted to JSON.
Here is my code, if anyone can make a suggestion. D_Type from table 2 is what I am trying to bind directly to the column:
#(Html.Kendo().Grid<ProjectName.Models.Table1>()
.Name("grid")
.Scrollable()
.ColumnMenu()
.Reorderable(reorder => reorder.Columns(true))
.Columns(columns =>
{
columns.Bound(c => c.P_Name);
columns.Bound(c => c.E_Name);
//Cannot be directly bound to a column because it is part of Table2 table
columns.Bound(c => c.TypeId).Title("Type").ClientTemplate("#= D_Type #").Filterable(false);
columns.Command(command => command.Custom("Details").Click("showDetails")).Title("Results").Width(80);
columns.Bound(c => c.Destination);
columns.Bound(c => c.Location);
columns.Bound(c => c.Version);
columns.Bound(c => c.StartDt);
columns.Bound(c => c.EndDt);
columns.Bound(c => c.StartDt).Title("Duration").ClientTemplate("#: calcDuration(StartDt, EndDt) #").Sortable(false).Filterable(false);
columns.Bound(c => c.);
columns.Bound(c => c.MiscNotes).ClientTemplate("#: errorDisplay(ResultObject) # ").Sortable(false).Filterable(false);
})
//Style dictates full grid height
.HtmlAttributes(new { style = "height: 725px;" })
.Filterable()
.Resizable(resize => resize.Columns(true))
.Sortable(sortable => sortable
.AllowUnsort(true)
.SortMode(GridSortMode.SingleColumn))
.Pageable(pageable => pageable
.Refresh(false)
.PageSizes(true)
.ButtonCount(5))
.Events(e => e.DataBound("onDataBound"))
.DataSource(dataSource => dataSource
.Ajax()
.Sort(sort => sort.Add("StartDt").Descending())
.Read(read => read.Action("Project_Read", "Grid"))
.PageSize(20)
.ServerOperation(true)
)
)
Don't bind your grid to ProjectName.Models.Table1.
Instead, bind it to a ViewModel that contains the fields from Table1 and the field from Table2 that you want to display in the Grid, i.e.
public class SpecificGridViewModel
{
public string P_Name { get; set; }
// Other fields you want from Table1
// ...
// PLUS the field(s) you want from the other, joined table.
public string D_Type { get; set; }
}
Then you have your Project_Read method return a list of these ViewModels that you have constructed from your LINQ query instead of a list of Table1s.
i.e. write a LINQ query that returns the exact data you want(data from Table1 joined with Table2.D_Type via Table1.TypeID) and return a result set of custom ViewModel that you create to hold the data from the query and then bind your grid to that model instead of the "raw" Table1 model.
I just want to display a GUID from my model in a Kendo grid in the view, but I am getting this error each time:
The model item passed into the dictionary is of type 'System.Guid',
but this dictionary requires a model item of type 'System.String'.
This is my grid code:
#(Html.Kendo().Grid(Model.revisions)
.Name("RevisionsGrid")
.Columns(columns =>
{
columns.Bound(p => p.RevisionInfo.Id).Title("Revision ID");
columns.Bound(p => p.Accident.Id).Title("Accident ID")
.ClientTemplate("#= (Accident.Id == null) ? '' : Accident.Id.toString() #");
columns.Bound(p => p.RevisionInfo.RevisionDate).Title("Date Modified");
columns.Bound(p => p.RevisionInfo.User.Name).Title("By User");
columns.Command(command => command.Custom("ViewPdf").Text("View PDF").Click("getPdf"));
})
.Selectable()
.Pageable(p => p.PageSizes(new[] { 5, 10, 25 }))
.DataSource(dataSource => dataSource
.Server()
.Model(model =>
{
model.Id(p => p.RevisionInfo.Id);
model.Field(p => p.Accident.Id).DefaultValue(Guid.NewGuid());
}))
The problem is with the second column which is bound to Accident.Id, a GUID type. My attempts at fixing this included adding the ClientTemplate to that column & adding a default value for it, but neither of these helped. I also tried just adding ToString() in the column definition but then I get a different error about .Bound() only taking a property access method as an argument.
Is there some place to convert the GUID to a string in order to display it here?
I figured it out. In order to have the Kendo grid accept something that's not a string you need to specify a template for the column, in which you can call ToString(). I couldn't call it in binding.
columns.Bound(p => p.Accident.Id).Title("Accident ID")
.Template(p => p.Accident.Id.ToString());