ForeignKey displays a textbox instead of dropdownlist - c#

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"])
)

Related

Telerik Grid, Detail view - how to specify route values

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.

Kendo UI MVC - Grid Paging, Sorting, Refreshing not working with WebAPI binding

When I set the datasource to WebAPI binding, the HTTP GET is being invoked on the controller and it returns the correct data. The problem is that my Kendo Grid is not binding the data correctly, instead I get an empty grid as a result.
#(Html.Kendo().Grid(Model)
.Name("Accounts")
.Columns(columns =>
{
columns.Bound(c => c.Description).Title("Account Name");
columns.ForeignKey(c => c.Type, (System.Collections.IEnumerable)ViewData["accountTypes"], "Id", "Name").Title("Account Type");
columns.ForeignKey(c => c.Currency, (System.Collections.IEnumerable)ViewData["currencyTypes"], "Id", "Name").Title("Account Currency");
columns.Command(command => { command.Edit(); command.Destroy(); }).Width(210);
})
.Sortable(sortable =>
{
sortable.SortMode(GridSortMode.SingleColumn);
sortable.AllowUnsort(false);
})
.Pageable(pageable => pageable
.Refresh(true)
.PageSizes(true)
.ButtonCount(5)
)
.ToolBar(toolbar => { toolbar.Create(); })
.Editable(editable => editable.Mode(GridEditMode.InLine))
.DataSource(dataSource => dataSource
.WebApi()
.Model(model =>
{
model.Id(p => p.Id);
model.Field(p => p.Currency).DefaultValue(0).Editable(true);
model.Field(p => p.Description).Editable(true);
model.Field(p => p.Type).Editable(true);
})
.ServerOperation(true)
.Read(read => read.Action("Get", "Accounts"))
.Create(create => create.Action("Post", "Accounts"))
.Update(update => update.Action("Put", "Accounts", new { id = "{0}" }))
.Destroy(destroy => destroy.Action("Delete", "Accounts", new { id = "{0}" }))
.PageSize(10)
)
)
Controller
// GET: api/values
[HttpGet]
public DataSourceResult Get([DataSourceRequest]DataSourceRequest request)
{
return _context.Accounts.ToDataSourceResult(request);
}
I always get an HTTP 200 OK as a result of the paging or sorting command, but the grid is empty afterwards. The URL generated by Kendo is:
http://localhost:58829/Accounts/Get?sort=&page=1&pageSize=10&group=&filter=
Which actually returns JSON when I open it with a browser.
The problem seems to be that you are mixing two different ways to load the data. On the one hand you are passing the Model by param to the grid (this approach is used when ServerOperation = false) and on the other hand you are setting ServerOperation = true and specifying a read action.
The reason why the grid is empty in this case is probably because either the Model is empty.
Take a look at this demo example for a reference on how to implement the remote source databinding: http://demos.telerik.com/aspnet-core/grid/remote-data-binding
Example View:
Example controller:
Hope this helps KendoGrid is an awesome library but like many other libraries it could definitely use better exception handling and more user friendly exceptions :) In my opinion the grid should have shown an exception in this case.
The problem was this: when declaring the Kendo Grid and passing the Model as a parameter like so:
#(Html.Kendo().Grid(Model)
You need to remove the .Read() action, and make sure to use .ServerOperation(false). This works either with WebApi binding or Ajax binding:
.DataSource(dataSource => dataSource
.WebApi() // also works with .Ajax()
.Model(model =>
{
model.Id(p => p.Id);
}
)
.ServerOperation(false)
.Create(create => create.Action("Post", "Invoices"))
.Update(update => update.Action("Put", "Invoices", new { id = "{0}" }))
.Destroy(destroy => destroy.Action("Delete", "Invoices", new { id = "{0}" }))
.PageSize(10)
)
Also, the DataSourceResult Get() method can be removed.

Columns.Bound cannot resolve symbol 'Bound'

I have a web page that has some Kendo controls like dropdown and button working successfully, but adding a Grid is causing a problem.
#(Html.Kendo().Grid(Model).Name("grid").Columns(columns =>
{
columns.Bound(stuff => stuff.FirstColumn).Width(200);
columns.Bound(stuff => stuff.SecondColumn).Width(200);
columns.Bound(stuff => stuff.HiddenColumn).Hidden;
columns.Bound(stuff => stuff.ThirdVisibleColumn).Width(200);
})
.Pagable()
.Sortable()
)
At design time, the .Bound method is showing in red font with the tooltip Cannot resolve the symbol 'Bound', and the properties of Stuff (e.g. .FirstColumn) are also in red with similar messages.
Compilation Error
Description: An error occurred during the compilation of a resource required to service this request. Please review the following specific error details and modify your source code appropriately.
Compiler Error Message: CS1977: Cannot use a lambda expression as an argument to a dynamically dispatched operation without first casting it to a delegate or expression tree type
This problem first showed up in another project, so as a test I created a new Telerik prject and added just the minimum required to reproduce the problem in the hope that a newly created project would highlight where the original one had failed. No such luck.
Thanks in advance.
If you pass the model like this it needs to be of type IEnumerable (or similar).
This works for me:
#model IEnumerable<SomeModel>
#(Html.Kendo().Grid(Model)
.Name("grid")
.Columns(columns =>
{
columns.Bound(stuff => stuff.FirstColumn).Width(200);
columns.Bound(stuff => stuff.SecondColumn).Width(200);
columns.Bound(stuff => stuff.HiddenColumn).Hidden();
columns.Bound(stuff => stuff.ThirdVisibleColumn).Width(200);
})
.Pageable()
.Sortable()
)
Also you can pass model like:
#(Html.Kendo().Grid<SomeModel>().Name("grid")
.DataSource(src => src.Ajax().Read(read => read.Action("Action", "Controller"))
.Columns(col =>
{
col.Bound(e => e.Name);
col.Bound(e => e.Age);
col.Bound(e => e.ID);
})
.Selectable()
.Scrollable()
)

Saving to many rows to database

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... :)

Add delete option to Kendo Grid

I have a Kendo UI Grid which displays some data. But now i need to add a delete option, so rows can be deleted as well. But how does this work?
I have added a Destroy method to the Grid. But that's just so it knows what Action to call.
How can i add a delete icon for each row for example to the grid? Or how does this normally work in a Kendo Grid?
This is the code i have so far:
#(Html.Kendo().Grid<DescriptorWithResource>()
.Name("grid")
.PrefixUrlParameters(false)
.Columns(columns =>
{
columns.Bound(x => x.Code).Title(Html.GetResource(KnownComponent, "ManagedDescriptorCode")).Width(250);
columns.Bound(x => x.Description).Title(Html.GetResource(KnownComponent, "ManagedDescriptorDescription")).Width(500);
})
.Pageable(pager => pager.Info(true)
.Refresh(false)
.PageSizes(false)
.PreviousNext(false)
.Numeric(false)
.Enabled(true)
.Messages(m => m.Display(#Html.GetResource(KnownComponent, "Label_TotalRecordsResource"))))
.Scrollable(scrollable => scrollable.Virtual(true))
.Selectable(selectable => selectable.Enabled(false))
.Events(e => e.DataBound("window.KendoExtensions.bindHoverEffect"))
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(50)
.Events(e => e
.RequestStart("window.Management.onDataSourceBinding")
.Error("window.Management.onDataSourceError"))
.Read(read => read.Action("ResultData", "Management"))
.Destroy(destroy => destroy.Action("DeleteRow", "Management"))) // <-- Added
)
You need to declare it via the Command builder.
columns => columns.Command(cmd=>cmd.Destroy())
You can add a html template for that particular column for each rows. In the html template you can have a button or link for the delete. ON CLICK of this button/link you can call your action.
template: '<input type="button" data-id=ID value="Delete" class="popupbutton" id="delButton" onclick="javascript:CheckAck(this);" id="Delete" /><br/>

Categories

Resources