I need to send a model to my controller action. I have created a Kendo grid:
Html.Kendo().Grid<XXXX.WebUI.Models.Employees.LocationsListViewModel>()
.Name("EmployeeLocationsGrid")
.Columns(columns => {
columns.Select().Width(45);
columns.Bound(c => c.UIDEmployee).Visible(false);
columns.Bound(c => c.UIDEmployee_Location).Title("Id").Width(50);
if (Model.LocationsEntities != null)
{
columns.ForeignKey(f => f.UIDLocation, Model.LocationsEntities?.Items, "UIDEntity", "Name")
.Title("Location")
.EditorTemplateName("FieldListLocations")
.EditorViewData(new { locations = Model.LocationsEntities.Items })
.Width(200);
}
if (Model.LocationsEntities != null)
{
columns.ForeignKey(f => f.UIDSublocation, Model.SublocationsEntities?.Items, "UIDEntity", "Name")
.Title("Sublocation")
.EditorTemplateName("FieldListSublocations")
.EditorViewData(new { sublocations = Model.SublocationsEntities.Items })
.Width(200);
}
columns.Bound(c => c.Main)
.Title("Main")
.EditorTemplateName("FieldCheckBox")
.ClientTemplate("#= Main ? 'Yes' : 'No' #")
.Width(100);
columns.Bound(c => c.PercentageOfDedication)
.Title("% Dedication")
.EditorTemplateName("FieldNumericTextBox")
.Format("{0} %")
.Width(200);
columns.Bound(c => c.StartDate)
.Title("Start Date")
.ClientTemplate("#= kendo.toString(kendo.parseDate(StartDate), 'dd/MM/yyyy') #")
.EditorTemplateName("FieldDateOnlyPicker")
.Width(200);
columns.Bound(c => c.EndDate)
.Title("End Date")
.ClientTemplate("#= EndDate != null ? kendo.toString(kendo.parseDate(EndDate), 'dd/MM/yyyy') : '<strong>Currently</strong>' #")
.EditorTemplateName("FieldDateOnlyPicker")
.Width(200);
columns.Bound(c => c.Comments)
.Title("Comments")
.EditorTemplateName("FieldTextArea")
.Width(250);
columns.Command(command => {
command.Edit().Text(" ").UpdateText(" ").CancelText(" ").IconClass("bi bi-pencil-square").HtmlAttributes(new { @class = "btn btn-outline-primary", title = "Edit" });
command.Custom("deleteLocation")
.Click("function(e) { var dataItemLoc = this.dataItem($(e.target).closest('tr')); window.i3.OnDeleteEmployeeLocation(dataItemLoc); }")
.Text(" ").IconClass("bi bi-trash3")
.HtmlAttributes(new { @class = "btn btn-outline-primary", title = "Delete" });
}).Title("Actions");
})
.NoRecords(s => s.Template("<span class='ms-3 mt-3'><i class='bi bi-people-fill me-2'></i><strong>This employee was not assigned to any location.</strong></span>"))
.AutoBind(true)
.Editable(editable => editable.Mode(GridEditMode.InLine))
.Sortable(sorting => sorting.Enabled(true))
.Selectable(selectable => selectable.Mode(GridSelectionMode.Multiple).DragToSelect(false))
.Events(events => events
.Sort("window.i3.OnColumnSorted").Save("window.i3.OnSaveLocation")
)
.DataSource(ds => ds
.Ajax()
.Model(gridModel =>
{
gridModel.Id(entity => entity.UIDEmployee_Location);
gridModel.Field(p => p.UIDEmployee_Location).Editable(false);
gridModel.Field(p => p.UIDEmployee).Editable(false).DefaultValue(Model.UIDEmployee);
gridModel.Field(p => p.UIDLocation).Editable(true);
gridModel.Field(p => p.UIDSublocation).Editable(true);
gridModel.Field(p => p.UIDStatus).Editable(false);
gridModel.Field(p => p.UIDPosition).Editable(false);
})
.Read(r => r.Action("GetAllEmployeeLocations", "Employees", new { EmployeeID = Model.UIDEmployee }))
.Events(events => events
.RequestEnd("window.i3.OnRequestEndLocation")
)
.PageSize(10)
)
)
This data reaches me at this event where I process it:
public OnSaveLocation(e: kendo.ui.GridSaveEvent): void {
e.preventDefault();
const gridLocation = $("#EmployeeLocationsGrid").data("kendoGrid");
const locationsItems: LocationsListViewModel[] = (gridLocation?.dataSource.data() as unknown) as LocationsListViewModel[];
let newLocItem: LocationsListViewModel = (e.model as any) as LocationsListViewModel;
// Fix Date
let startLocationDateNew = new Date(newLocItem.StartDate);
let endLocationDateNew = new Date(newLocItem.EndDate);
let offsetLocationNew = startLocationDateNew.getTimezoneOffset();
startLocationDateNew = new Date(startLocationDateNew.getTime() - (offsetLocationNew * 60 * 1000));
endLocationDateNew = new Date(endLocationDateNew.getTime() - (offsetLocationNew * 60 * 1000));
let newLocationItem: LocationsListViewModel = {
UIDEmployee_Location: newLocItem.UIDEmployee_Location,
UIDEmployee: newLocItem.UIDEmployee,
UIDLocation: newLocItem.UIDLocation,
UIDSublocation: newLocItem.UIDSublocation,
UIDPosition: newLocItem.UIDPosition,
Main: newLocItem.Main,
PercentageOfDedication: newLocItem.PercentageOfDedication,
StartDate: startLocationDateNew.toISOString().split('T')[0],
EndDate: endLocationDateNew.toISOString().split('T')[0],
UIDStatus: newLocItem.UIDStatus,
Comments: newLocItem.Comments
};
}
All the data is well collected except Sublocations is set to null. Where it should be an int ID. I share with you the Template and the model:
@using XXXX.Application.Application.Maintenances.DTOs;
@model int?
@(Html.Kendo().DropDownListFor(m => m)
.DataTextField("Name")
.DataValueField("UIDEntity")
.OptionLabel("Select...")
.BindTo((IEnumerable<GenericMaintenanceEntityDTO>)ViewData["sublocations"]!)
)
@using XXXX.Application.Application.Maintenances.DTOs;
@model int
@(Html.Kendo().DropDownListFor(m => m)
.DataTextField("Name")
.DataValueField("UIDEntity")
.OptionLabel("Select...")
.BindTo((IEnumerable<GenericMaintenanceEntityDTO>)ViewData["locations"]!)
)
interface LocationsListViewModel {
UIDEmployee_Location: number;
UIDEmployee: number;
UIDLocation: number;
UIDSublocation: number;
UIDPosition: number;
Main: boolean;
PercentageOfDedication: string;
StartDate: string;
EndDate: string;
UIDStatus: number;
Comments: string;
}
I have been looking for the problem for quite some time but I can't find it. Can someone help me?
Thanks
I am migrating a WebForms application to ASP.NET Core MVC
In that application a radmenu is used.
Radmenu had a string property "value".
A sort of free to use property.
Is there any way to achieve this in a core MenuItem?
Hello,
I have Html.Kendo().Grid with checkbox column based on field(IsEnabled) is true that particular grid cell with check box needs to allow the user selection. if field(IsEnabled) is false that particular cell should be disabled and not allow the user to select or deselect.
The issue I'm facing is, it is allow to select the check box in second click only. not allowing to select in single click on that check box
sample code which I am using:
columns.Bound(c => c.IsEnabled)I've pulled ViewModel objects into my selectable grid. After a user selects rows, a submit button allows an ajax call which will post the selected objects (rows) to a controller method:
function submitAddressImport() {
var grid = $("#groupAddressesImportGrid").data('kendoGrid');
var selectedItems = grid.selectedKeyNames();
var actualItems = [];
if (selectedItems.length > 0) {
selectedItems.forEach(function(key) {
actualItems.push(grid.dataSource.get(key));
});
}
kendo.ui.progress($("#groupAddressesImportGrid"), true);
for (var i = 0; i < actualItems.length; i++) {
$.ajax({
type: "POST",
url: "@Url.Action("AddAddress", "Address")",
contentType: "application/json;",
data: actualItems[i], // JSON.stringify(actualItems[i]) avoids console error
traditional: false,
success: function (data) {
...
},
error: function (data) {
...
},
timeout: function (data) {
...
}, complete: function () {
...
}
});
}
closeGroupAddresspopup()
}
What is most curious about this error is that it is avoided if I use JSON.stringify() to convert the object to a JSON string. My model expects an object of a class, and if a stringified object is sent the object itself will not be null but will have all properties set to null.
When troubleshooting this, I removed the call to JSON.stringify() and encountered the console error:
Uncaught TypeError: Cannot read properties of undefined (reading 'field')
Why does this error occur when JSON.stringify() is not used, and how can it be avoided?
My grid is configured as follows:
@(
Html.Kendo().Grid(Model.groupAddresses)
.Name("groupAddressesImportGrid")
.HtmlAttributes(new { @class = "table-cell" })
.Columns(columns =>
{
columns.Select().Width(50);
columns.Bound(obj => obj.AddressType).Title("Type").Width(60);
columns.Bound(obj => obj.PrimaryField).Title("Primary");
columns.Bound(obj => obj.Address1).Title("Address");
columns.Bound(obj => obj.AddressCity).Title("City");
columns.Bound(obj => obj.State).Title("State");
columns.Bound(obj => obj.ZipCode).Title("Zip Code");
columns.Bound(obj => obj.County).Title("County");
})
.Sortable(_ => _.AllowUnsort(true))
.Resizable(resizable => resizable.Columns(true))
.Navigatable()
.Filterable()
.Scrollable()
.Resizable(resize => resize.Columns(true))
.Events(ev=>ev.Change("handleCheckBox"))
.PersistSelection()
.DataSource(dataSource => dataSource
.Ajax()
.Model(model => model.Id(p => p.AddressId))
)
)
I'm using a Razor partial to create a navigation menu being served from a database. It's rendering the data from the database without issue, however, the children items are being displayed instead of only showing on hover / click.
When I load the app, the children items are already showing and attempting to collapse the About Root by clicking it has no result. Is it possible that the issue is related to Partial rendering?
if (memoryCache.TryGetValue(NavigationRepository.cacheKey, out List<Navigation> navItems))
{
@(
Html.Kendo().Menu()
.Name("navigation")
.Items(items =>
{ //Render data that is loaded into .NET IMemoryCache on startup and kept up-to-date through the repository
foreach (var nav in navItems.Where(q => q.ParentNavigationId == null)) //Renders top level objects only
{
items.Add()
.Text(nav.Text)
.Url(nav.Link)
.Items(children =>
{ //Render child objects by matching elements that reference the top level object Id
foreach (var subNav in navItems.Where(q => q.ParentNavigationId == nav.Id))
{
children.Add()
.Text(subNav.Text)
.Url(subNav.Link);
}
});
}
})
.Direction(MenuDirection.Bottom)
.Orientation(MenuOrientation.Horizontal)
.OpenOnClick(true)
.CloseOnClick(true)
.HoverDelay(100)
.Animation(a =>
{
a.Enable(true);
a.Open(effect =>
{
effect.Expand(ExpandDirection.Vertical);
effect.Duration(500);
});
a.Close(effect =>
{
effect.Duration(300);
});
})
.Deferred(true) // JS error of kendo not found if this is not enabled
)
}
This partial is then rendered into the _Layout.cshtml through the below code.
<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">When row dragging and dropping the second time the UI doesnt refelct the change.
If I have an event I can see the drag and drop correctly, but the UI leaves the dragged row where it was
the code is simple
@(Html.Kendo().Grid<OncostVM>()
.Name("OncostGrid")
.DataSource(data => data
.Ajax()
.Read(read => read.Action("Read", "Oncost"))
.PageSize(10)
)
.Columns(columns =>
{
columns.Bound(c => c.OncostId).Title("Id").Width(80).Filterable(false);
columns.Template(@<text> </text>).Draggable(true).Width(50);
columns.Bound(c => c.Name).Filterable(false);
columns.Bound(c => c.Visible).Width(120).Filterable(false).YesNo("Visible");
columns.Bound(c => c.Active).Width(120).YesNo("Active");
})
.Filterable()
.Sortable()
.Pageable(page => page.Refresh(true))
.Reorderable(order => order.Rows(true))
@* .Events(ev => { ev.RowReorder("dragRow"); }) *@
)
https://i.imgur.com/GiD6Pi2.gif
Hi!
I use a lot of forms (created using HtmlHelper) inside templates used by various other elements (mainly inside TileLayouts).
e.g.:
public record SettingsViewModel
{
[DataType(DataType.Password)]
public string Password { get; set; } = null!;
}
<script id="settings-template" type="text/x-kendo-template">
@(Html.Kendo().Form<settingsViewModel>()
.Name("settingsForm")
.FormData(Model.Settings)
.Layout("grid")
.Grid(g => g.Cols(2).Gutter(5))
.HtmlAttributes(new { method = "POST", style = "width: 100%;" })
.Validatable(v =>
{
v.ValidateOnBlur(false);
v.ValidationSummary(true);
})
.Items(items =>
{
items.Add().Field(f => f.Password).Label("Password");
})
.ToClientTemplate()
@* .ToString()
.Replace("#", "\\#") *@
)
</script>
<div class="k-d-flex-col k-justify-content-center">
@(Html.Kendo().TileLayout()
.Name("settings")
.Columns(5)
.RowsHeight("auto")
.Containers(c =>
{
...
c.Add().BodyTemplateId("settings-template").ColSpan(4).RowSpan(1);
...
})
)
</div>
Many of these forms requires to accept text boxes (like passwords) which should accept "#" in their content.
Saving works perfect but when rendering the Form I always get an exception. Please see below error:
Uncaught Error: Invalid template:'
<form id="settingsForm" method="POST" name="settingsForm" style="width: 100%;"></form><script>kendo.syncReady(function(){jQuery("\#settingsForm").kendoForm({"validatable":{"validateOnBlur":false,"validationSummary":{}},"formData":{"Password":"bla#bla","Id":0},"layout":"grid","grid":{"cols":2,"gutter":5},"serverErrors":{},"items":[{"field":"Password","label":{"text":"Password"},"editorOptions":{},"validation":{"data-val":"true","data-val-required":"The Password field is required.","type":"password"},"shouldRenderHidden":true}]});});<\/script>
' Generated code:'var $kendoOutput, $kendoHtmlEncode = kendo.htmlEncode;with(data){$kendoOutput='\n <form id="settingsForm" method="POST" name="settingsForm" style="width: 100%;"></form><script>kendo.syncReady(function(){jQuery("#settingsForm").kendoForm({"validatable":{"validateOnBlur":false,"validationSummary":{}},"formData":{"Password":"bla';bla","Id":0},"layout":"grid","grid":{"cols":2,"gutter":5},"serverErrors":{},"items":[{"field":"Password","label":{"text":"Password"},"editorOptions":{},"validation":{"data-val":"true","data-val-required":"The Password field is required.","type":"password"},"shouldRenderHidden":true}]});});<\/script>
;$kendoOutput+=;}return $kendoOutput;'
at Object.compile (kendo.all.js:322401:19)
at init._initContainers (kendo.all.js:322401:19)
at new init (kendo.all.js:322401:19)
at HTMLDivElement.<anonymous> (kendo.all.js:322401:19)
at Function.each (jquery.min.js:2:2898)
at n.fn.init.each (jquery.min.js:2:846)
at e.fn.<computed> [as kendoTileLayout] (kendo.all.js:322401:19)
.......
Any idea how to fix that on the client-side (and not need to escape each property I want to accept "#" at server-side) ?
Thanks