Using a Grid to Edit the Scheduler Resources
Environment
Product | Telerik UI for ASP.NET Core Scheduler |
Product Version | Created with version 2024.4.1112 |
Description
How can I use the ASP.NET Core Grid component to edit the ASP.NET Core Scheduler resources?
By design, the user can edit the resources assigned to the Scheduler events. However, the default editor template of the Scheduler does not provide an editor that allows the users to edit the available resources.
For example:
- To add a new resource that can be assigned to a specified event.
- To edit the
Text
,Value
, orColor
fields of the existing resource items. - To delete a resource so it does not appear anymore as an available option in the resources DropDownList.
Solution
Follow the steps below to create a custom editor template for the Scheduler events that contains an Edit Attendees button, which opens a Window component with an InCell editable Grid used for editing the Scheduler resources.
-
Configure the resources to bind to remote data by using a Custom DataSource. This way, when the resources are modified through the Grid, the changes will be applied to the resources collection.
@(Html.Kendo().Scheduler<MeetingViewModel>() .Name("scheduler") .Editable(editable => { editable.TemplateName("CustomEditorTemplate"); }) .Resources(resource => { resource.Add(m => m.Attendees) .Title("Attendees") .Multiple(true) .DataTextField("Text") .DataValueField("Value") .DataColorField("Color") .DataSource(ds => ds .Custom() .Type("aspnetmvc-ajax") // Required in order to work with ToDataSourceResult() method. .Transport(transport => transport.Read(read => read.Action("Read_Attendees", "Home"))) .Schema(schema => schema //Required in order to work with ToDataSourceResult .Data("Data") .Total("Total") .Errors("Errors") .Model(model => { model.Id("Value"); model.Field("Value", typeof(int)); model.Field("Text", typeof(string)); model.Field("Color", typeof(string)); }) ) ); }) ...// Additional configuration. )
@addTagHelper *, Kendo.Mvc <kendo-scheduler name="scheduler"> <editable template-view="await @Html.PartialAsync("~/Views/Shared/EditorTemplates/TagHelper_CustomEditorTemplate.cshtml")"> </editable> <resources> <resource field="Attendees" title="Attendees" multiple="true" datatextfield="Text" datavaluefield="Value" datacolorfield="Color"> <datasource type="DataSourceTagHelperType.Custom"> <transport> <read url="@Url.Action("Read_Attendees", "Home")" /> </transport> <schema data="Data" total="Total" errors="Errors"> <model id="Value"> <fields> <field name="Value" type="number" /> <field name="Text" type="string" /> <field name="Color" type="string" /> </fields> </model> </schema> </datasource> </resource> </resources> <!-- Other configuration --> </kendo-scheduler>
public virtual JsonResult Read_Attendees([DataSourceRequest] DataSourceRequest request) { return Json(GetAll().ToDataSourceResult(request)); } private static IList<Attendee> GetAll() { IList<Attendee> result = new List<Attendee>(); ... // Populate the "result" with the data. return result; }
Create a custom editor template for the Scheduler. For more information, refer to the implementing custom editors for the Scheduler events documentation.
-
Add a MultiSelect editor for the Attendees resources in the custom editor template and configure it for remote data binding.
<div class="k-edit-label"> @(Html.LabelFor(model => model.Attendees)) </div> <div data-container-for="Attendees" class="k-edit-field"> <div style="width: 280px; display: inline-block"> @(Html.Kendo().MultiSelectFor(model => model.Attendees) .HtmlAttributes(new { data_bind = "value:Attendees"}) .DataTextField("Text") .DataValueField("Value") .ValuePrimitive(true) .TagTemplate("<span class='k-scheduler-mark' style='background-color:\\#= data.Color?Color:'' \\#'></span>\\#=Text\\#") .ItemTemplate("<span class='k-scheduler-mark' style='background-color:\\#= data.Color?Color:'' \\#'></span>\\#=Text\\#") .DataSource(ds => ds .Custom() .Type("aspnetmvc-ajax") .Transport(transport => transport.Read(read => read.Action("Read_Attendees", "Home"))) .Schema(schema => schema .Data("Data") .Total("Total") .Errors("Errors") .Model(model => { model.Id("Value"); model.Field("Value", typeof(int)); model.Field("Text", typeof(string)); model.Field("Color", typeof(string)); }) ) ) ) </div> </div>
@addTagHelper *, Kendo.Mvc <div class="k-edit-label"> <label asp-for="Attendees"></label> </div> <div data-container-for="Attendees" class="k-edit-field"> <div style="width: 280px; display: inline-block"> <kendo-multiselect for="Attendees" is-in-client-template="true" datavaluefield="Value" datatextfield="Text" value-primitive="true" item-template="<span class='k-scheduler-mark' style='background-color:\\#= data.Color?Color:'' \\#'></span>\\#=Text\\#" tag-template="<span class='k-scheduler-mark' style='background-color:\\#= data.Color?Color:'' \\#'></span>\\#=Text\\#"> <datasource type="DataSourceTagHelperType.Custom"> <transport> <read url="@Url.Action("Read_Attendees", "Home")" /> </transport> <schema data="Data" total="Total" errors="Errors"> <model id="Value"> <fields> <field name="Value" type="number"></field> <field name="Text" type="string"></field> <field name="Color" type="string"></field> </fields> </model> </schema> </datasource> </kendo-multiselect> </div> </div>
-
Add a button after the MultiSelect editor that will open the Window with the Grid. Also, define the InCell editable Grid and wrap it into a
<div>
element with a class insertNewAttendeeDialog. Finally, add Save changes and Cancel changes buttons below the Grid. The Save changes button will save the Grid changes, close the Window with the Grid, refresh the options of the MultiSelect editor used for the resources, and fetch the latest data for the resources collection.<div data-container-for="Attendees" class="k-edit-field"> <div style="width: 280px; display: inline-block"> @(Html.Kendo().MultiSelectFor(model => model.Attendees) ...// Additional configuration. ) </div> <button class="k-button k-button-md k-rounded-md k-button-solid k-button-solid-primary" style="float:right;" id="editAttendees">Edit attendees</button> <div id="insertNewAttendeeDialog"> <div id="editResources"></div> <em>* closing the window will cancel the changes</em> @(Html.Kendo().Grid<Telerik.Examples.Mvc.Areas.SchedulerEditingResources.Models.Attendee>() .Name("AttendeeEditor") .Columns(columns => { columns.Bound(p => p.Value).Width(100); columns.Bound(p => p.Text).Width(100); columns.Bound(p => p.Color).Width(100); columns.Command(command => command.Destroy()).Width(100); }) .Navigatable() .ToolBar(toolbar => { toolbar.Create(); }) .Editable(editable => editable.Mode(GridEditMode.InCell)) .DataSource(ds => ds .Ajax() .Model(model => { model.Id(m => m.Value); model.Field(m => m.Value).Editable(false); }) .Read(read => read.Action("Read_Attendees", "Home")) .Create(create => create.Action("Create_Attendees", "Home")) .Destroy(destroy => destroy.Action("Destroy_Attendees", "Home")) .Update(update => update.Action("Update_Attendees", "Home")) ) .ToClientTemplate() ) <br /> <button id='saveAttendees' class="k-button k-button-md k-rounded-md k-button-solid k-button-solid-primary">Save changes</button> <button id='cancelAttendees' class="k-button k-button-md k-rounded-md k-button-solid k-button-solid-base">Cancel changes</button> </div> </div>
@addTagHelper *, Kendo.Mvc <div data-container-for="Attendees" class="k-edit-field"> <div style="width: 280px; display: inline-block"> <kendo-multiselect for="Attendees" is-in-client-template="true"> <!--Other configuration--> </kendo-multiselect> </div> <button class="k-button k-button-md k-rounded-md k-button-solid k-button-solid-primary" style="float:right;" id="editAttendees">Edit attendees</button> <div id="insertNewAttendeeDialog"> <div id="editResources"></div> <em>* closing the window will cancel the changes</em> <kendo-grid name="AttendeeEditor" navigatable="true" is-in-client-template="true"> <datasource type="DataSourceTagHelperType.Ajax"> <schema data="Data" total="Total"> <model id="Value"> <fields> <field name="Value" type="number" editable="false"></field> </fields> </model> </schema> <transport> <read url="@Url.Action("Read_Attendees","Home")"/> <create url="@Url.Action("Create_Attendees","Home")"/> <update url="@Url.Action("Update_Attendees","Home")"/> <destroy url="@Url.Action("Destroy_Attendees","Home")"/> </transport> </datasource> <columns> <column field="Value" width="100"/> <column field="Text" width="100"/> <column field="Color" width="100"/> <column width="100"> <commands> <column-command text="Delete" name="destroy"></column-command> </commands> </column> </columns> <toolbar> <toolbar-button name="create"></toolbar-button> </toolbar> <editable mode="incell"/> </kendo-grid> <br /> <button id='saveAttendees' class="k-button k-button-md k-rounded-md k-button-solid k-button-solid-primary">Save changes</button> <button id='cancelAttendees' class="k-button k-button-md k-rounded-md k-button-solid k-button-solid-base">Cancel changes</button> </div> </div>
-
When the custom editor of the Scheduler is loaded, initialize the Window component that holds the Grid with jQuery.
//CustomEditorTemplate.cshtml <script> (function () { var grid = $(document.getElementById("AttendeeEditor")).getKendoGrid(); // Get a reference to the Grid. var multi = $(document.getElementById("Attendees")).getKendoMultiSelect(); // Get a reference to the MultiSelect. var scheduler = $(document.getElementById("scheduler")).getKendoScheduler(); // Get a reference to the Scheduler. var dialog = $(document.getElementById("insertNewAttendeeDialog")).kendoWindow({ // Initialize the Window. title: "Insert New Attendee", modal: true, movable: true, visible: false, close: function () { /* Cancel Grid changes. */ grid.cancelChanges(); }, open: function () { this.center(); // Center the Window. grid.dataSource.read(); // Request the Grid's data. } }).getKendoWindow(); })(); </script>
-
Handle the
click
events of the Edit attendees, Save changes, and Cancel changes buttons.//CustomEditorTemplate.cshtml <script> (function () { var grid = $(document.getElementById("AttendeeEditor")).getKendoGrid(); // Get a reference to the Grid. var multi = $(document.getElementById("Attendees")).getKendoMultiSelect(); // Get a reference to the MultiSelect. var scheduler = $(document.getElementById("scheduler")).getKendoScheduler(); // Get a reference to the Scheduler. var dialog = $(document.getElementById("insertNewAttendeeDialog")).kendoWindow({ ... }).getKendoWindow(); $(document.getElementById("editAttendees")).on("click", function() { dialog.open(); // Open the Window with the Grid. }); $(document.getElementById("cancelAttendees")).on("click", function() { dialog.close(); // Close the Window with the Grid when the changes are cancelled. }); $(document.getElementById("saveAttendees")).on("click", function() { grid.dataSource.sync().then(function() { // Save all pending Grid changes. dialog.close(); // Close the Window with the Grid. multi.dataSource.read(); // Trigger the Read request of the MultiSelect editor to load the updated options. /* The index of the resource defined in the Scheduler configuration. */ var resourceIndex = 0; scheduler.resources[resourceIndex].dataSource.read(); // Trigger the Read request of the resources to load the updated options. }); }); })(); </script>
-
Handle the
Edit
event of the Scheduler and get a reference to the Window that contains the event's editors. Subscribe to itsclose
event and destroy the nested Window that holds the Grid.@(Html.Kendo().Scheduler<MeetingViewModel>() .Name("scheduler") .Events(e => e.Edit("onEdit")) ...// Additional configuration. ) <script type="text/javascript"> function onEdit(e) { var editorWindow = $(e.container).getKendoWindow(); // The main Window. editorWindow.bind("close", function () { destroyDialog(); // Destroy the Window with the Grid. }); } </script>
@addTagHelper *, Kendo.Mvc <kendo-scheduler name="scheduler" on-edit="onEdit"> <!-- Other configuration --> </kendo-scheduler> <script type="text/javascript"> function onEdit(e) { var editorWindow = $(e.container).getKendoWindow(); // The main Window. editorWindow.bind("close", function () { destroyDialog(); // Destroy the Window with the Grid. }); } </script>
<script> function destroyDialog() { var dialogElement = $(document.getElementById("insertNewAttendeeDialog")); dialogElement.getKendoWindow().destroy(); dialogElement.remove(); } </script>
For a runnable example, refer to the ASP.NET MVC application in the UI for ASP.NET MVC Examples repository. You can use this as a starting point to configure the same behavior in an ASP.NET Core project.