DropDownList in nested grid

4 posts, 0 answers
  1. James
    James avatar
    2 posts
    Member since:
    Jun 2016

    Posted 20 Jul Link to this post

    Hi,

    I'm looking for advice on how to add a dropdownlist to the following grid structure

    Here's the main grid/razor page

    @using Intranet.Models.Kendo
     
    <h2>Manage Eliminations</h2>
     
    @(Html.Kendo().Grid<KendoFullElimination>()
            .Name("grid")
            .Columns(columns =>
            {
                columns.Bound(c => c.Id).Title("Elimination Id");
                columns.Bound(c => c.Date).Title("Date To Process");
                columns.Command(command =>
                {
                    command.Destroy();
                    command.Edit();
                }).Width(250);
            })
            .HtmlAttributes(new { style = "height: 550px;" })
            .Scrollable()
            .Sortable()
            .Groupable()
            .Filterable()
            .Pageable(pageable => pageable
                .Refresh(true)
                .PageSizes(true)
                .ButtonCount(5))
            .ToolBar(toolbar => toolbar.Create())
            .Editable(editable => editable.Mode(GridEditMode.PopUp).TemplateName("eliminationTemplate").DisplayDeleteConfirmation(true).Window(w => w.Title("Elimination Details").Name("editWindow").HtmlAttributes(new { @style = "width:700px;" })))
            .DataSource(dataSource => dataSource
                .Ajax()
                .PageSize(25)
                .Events(events => events.Error("error_handler"))
                .Model(model =>
                {
                    model.Id(p => p.Id);
                    model.Field(x => x.Id).Editable(false);
                    model.Field(x => x.Date).Editable(false);
                })
                .Create(update => update.Action("Eliminations_Create", "Elimination"))
                .Read(read => read.Action("Eliminations_Read", "Elimination"))
                .Update(update => update.Action("Eliminations_Update", "Elimination"))
                .Destroy(update => update.Action("Eliminations_Delete", "Elimination"))
     
            )
    );
    <script type="text/javascript">
        $(document).ready(function () {
     
        });
        function error_handler(e) {
            if (e.errors) {
                var message = "Errors:\n";
                $.each(e.errors, function (key, value) {
                    if ('errors' in value) {
                        $.each(value.errors, function () {
                            message += this + "\n";
                        });
                    }
                });
                alert(message);
            }
        }
        function filterVarieties() {
            return {
                fruitId: $("#FruitId").val()
            };
        }
        function filterBlocks() {
            return {
                growerId: $("#GrowerId").val()
            };
        }
        function filterBlocks() {
            return {
                growerId: $("#GrowerId").val()
            };
        }
    </script>

    Here's the secondary grid, which as you can see is a template that's loaded in a popup when insert/updating the main grid

    @using Intranet.Models.Kendo
    @model Intranet.Models.Kendo.KendoFullElimination
    <div id="eliminationsEditForm">
        <h3>Elimination Edit Form</h3>
        <div>
            @Html.LabelFor(model => model.Date)
            @(Html.Kendo().DatePicker()
                  .Name("Date")
                  .HtmlAttributes(new { style = "width: 100%" })
            )
        </div>
        <label for="FieldForemanId">Select the Field Foreman</label>
        @(Html.Kendo().DropDownList()
              .Name("FieldForemanId") //The name of the DropDownList is mandatory. It specifies the "id" attribute of the widget.
              .DataTextField("DisplayName") //Specify which property of the Product to be used by the DropDownList as a text.
              .DataValueField("Id") //Specify which property of the Product to be used by the DropDownList as a value.
              .DataSource(source =>
              {
                  source.Read(read =>
                  {
                      read.Action("GetFieldForemanDropdown", "Elimination"); //Set the Action and Controller names.
                  })
                      .ServerFiltering(true); //If true, the DataSource will not filter the data on the client.
              }) //Pass the list of Products to the DropDownList.
              )
        <label for="GrowerId">Select the Grower</label>
        @(Html.Kendo().DropDownList()
              .Name("GrowerId") //The name of the DropDownList is mandatory. It specifies the "id" attribute of the widget.
              .DataTextField("DisplayName") //Specify which property of the Product to be used by the DropDownList as a text.
              .DataValueField("Id") //Specify which property of the Product to be used by the DropDownList as a value.
              .DataSource(source =>
              {
                  source.Read(read =>
                  {
                      read.Action("GetGrowerDropdown", "Elimination"); //Set the Action and Controller names.
                  })
                      .ServerFiltering(false); //If true, the DataSource will not filter the data on the client.
              }) //Pass the list of Products to the DropDownList.
              )
        <label for="BlockId">Select the Block</label>
        @(Html.Kendo().DropDownList()
              .Name("BlockId")
              .DataTextField("DisplayName")
              .DataValueField("Id")
              .DataSource(source =>
              {
                  source.Read(read =>
                  {
                      read.Action("GetBlockDropdown", "Elimination")
                          .Data("filterBlocks");
                  })
                  .ServerFiltering(false);
              })
            .Enable(false)
            .AutoBind(false)
              .CascadeFrom("GrowerId")
              .Value("")
              .HtmlAttributes(new { style = "width: 100%" })
        )
        <label for="Fruit">Select the Fruit</label>
        @(Html.Kendo().DropDownList()
              .Name("FruitId") //The name of the DropDownList is mandatory. It specifies the "id" attribute of the widget.
              .DataTextField("DisplayName") //Specify which property of the Product to be used by the DropDownList as a text.
              .DataValueField("Id") //Specify which property of the Product to be used by the DropDownList as a value.
              .DataSource(source =>
              {
                  source.Read(read =>
                  {
                      read.Action("GetFruitDropdown", "Elimination"); //Set the Action and Controller names.
                  })
                      .ServerFiltering(false); //If true, the DataSource will not filter the data on the client.
              }) //Pass the list of Products to the DropDownList.
        )
        <label for="FruitId">Select the Variety</label>
        @(Html.Kendo().DropDownList()
              .Name("VarietyId")
              .DataTextField("DisplayName")
              .DataValueField("Id")
              .DataSource(source =>
              {
                  source.Read(read =>
                  {
                      read.Action("GetVarietyDropdown", "Elimination")
                          .Data("filterVarieties");
                  })
                  .ServerFiltering(true);
              })
            .Enable(false)
            .AutoBind(false)
              .CascadeFrom("FruitId")
              .HtmlAttributes(new { style = "width: 100%" })
        )
        <div>
            @Html.LabelFor(model => model.HasChlorineApplied)
            @Html.CheckBoxFor(model => model.HasChlorineApplied)
        </div>
        <div>
            @Html.LabelFor(model => model.HasPolyWaxApplied)
            @Html.CheckBoxFor(model => model.HasPolyWaxApplied)
        </div>
        <div>
            @Html.LabelFor(model => model.HasExportWaxApplied)
            @Html.CheckBoxFor(model => model.HasExportWaxApplied)
        </div>
        <div>
            @Html.LabelFor(model => model.HasFruitCleanerApplied)
            @Html.CheckBoxFor(model => model.HasFruitCleanerApplied)
        </div>
        <div>
            @Html.LabelFor(model => model.IsPresureWashed)
            @Html.CheckBoxFor(model => model.IsPresureWashed)
        </div>
        <div>
            @Html.LabelFor(model => model.IsSmudgeOff)
            @Html.CheckBoxFor(model => model.IsSmudgeOff)
        </div>
        <div>
            @Html.LabelFor(model => model.HasSopp2Applied)
            @Html.CheckBoxFor(model => model.HasSopp2Applied)
        </div>
        <div>
            @Html.LabelFor(model => model.Comments)
     
        </div>
        <div>
            <label for="ticketNumbers">Select the ticket numbers related to this elimination</label>
            @(Html.Kendo().MultiSelect()
                  .Name("ticketNumbers") //The name of the MultiSelect is mandatory. It specifies the "id" attribute of the widget.
                  .DataTextField("DisplayName") //Specify which property of the Product to be used by the MultiSelect as a text.
                  .DataValueField("ID") //Specify which property of the Product to be used by the MultiSelect as a value.
                  .Filter(FilterType.Contains)
                  .DataSource(source =>
                  {
                      source.Read(read =>
                      {
                          read.Action("GetTicketsMultiSelect", "Elimination"); //Set the Action and Controller names.
                      })
                          .ServerFiltering(true); //If true, the DataSource will not filter the data on the client.
                  })
                  )
        </div>
        <div>
            <label for="RecordedCaretakingIssues">Caretaking Issues</label>
            @(Html.Kendo().Grid<KendoRecordedCaretakingIssue>()
                  .Name("recordedCaretakingIssuesGrid")
                  .Columns(columns =>
                  {
                      columns.Bound(c => c.IssueCaretaking).Title("Caretaking Issue").Width(150);
                      columns.Bound(c => c.Percentage).Title("Percentage").Width(150);
                      columns.Command(command =>
                      {
                          command.Destroy();
                          command.Edit();
                      }).Width(250);
                  })
                    .DataSource(ds => ds.Ajax()
                        .Read(r => r.Action("GetRecordedCareTakingIssuesForElimination", "Elimination", new { eliminationId = "#=Id#" }))
                        .Create(c => c.Action("CreateRecordedCareTakingIssuesForElimination", "Elimination"))
                        .Update(u => u.Action("ChangeRecordedCareTakingIssuesForElimination", "Elimination"))
                        .Destroy(d => d.Action("DeleteRecordedCareTakingIssuesForElimination", "Elimination"))
                        .Model(m => {
                            m.Id(l => l.IssueCaretaking.Id);
                        })
                    )
                    .ToolBar(tb => tb.Create())
                    .Scrollable()
                    .Sortable()
                    .Editable()
                    .ToClientTemplate()
     
     
                )
             
                     
        </div>
        <div>
            @Html.LabelFor(model => model.Comments)
            @Html.TextAreaFor(model => model.Comments, new {style = "width: 700px; height:200px;"})
        </div>
    </div>

    Here's the template I was hoping would load

    @(Html.Kendo().DropDownListFor(x => x)
        .Name("IssueCaretaking")
        .DataTextField("DisplayName")
        .DataValueField("Id")
        .DataSource(source =>
        {
            source.Read(read =>
            {
                read.Action("GetCaretakingIssueDropdown", "Elimination"); //Set the Action and Controller names.
            })
            .ServerFiltering(true); //If true, the DataSource will not filter the data on the client.
        })
        .SelectedIndex(0)
    )

    But...the grid loads okay (I haven't tested update and getting the ID from the elimination object yet).  When I attempt to add a KendoRecordedCaretakingIssue, the percentage loads but the dropdown does not.

     

    Here's the model, not sure if it matters or not

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
     
    namespace Intranet.Models.Kendo
    {
        public class KendoFullElimination
        {
            public int Id { get; set; }
            [DisplayName("Elimination Recording Date")]
            public DateTime Date { get; set; }
            [DisplayName("Has Chlorine Been Applied?")]
            public bool HasChlorineApplied { get; set; }
            [DisplayName("Has Poly Wax Been Applied?")]
            public bool HasPolyWaxApplied { get; set; }
            [DisplayName("Has Export Wax Been Applied?")]
            public bool HasExportWaxApplied { get; set; }
            [DisplayName("Has Fruit Cleaner Been Applied?")]
            public bool HasFruitCleanerApplied { get; set; }
            [DisplayName("Is This Pressure Washed?")]
            public bool IsPresureWashed { get; set; }
            [DisplayName("Is This Treated with Smudge Off?")]
            public bool IsSmudgeOff { get; set; }
            [DisplayName("Has Sopp2 Been Applied?")]
            public bool HasSopp2Applied { get; set; }
            [DisplayName("Please leave any comments")]
            public string Comments { get; set; }
            [DisplayName("Field Foreman")]
            public int FieldForemanId { get; set; }
            [DisplayName("Grower")]
            public int GrowerId { get; set; }
            [DisplayName("Block")]
            public int BlockId { get; set; }
            [DisplayName("Fruit")]
            public int FruitId { get; set; }
            [DisplayName("Variety")]
            public int VarietyId { get; set; }
            [DisplayName("Tickets")]
            public IEnumerable<int> TicketNumbers { get; set; }
     
            public IEnumerable<KendoRecordedCaretakingIssue> RecordedCaretakingIssues { get; set; }
        }
    }
     
    using System.ComponentModel.DataAnnotations;
     
    namespace Intranet.Models.Kendo
    {
        public class KendoRecordedCaretakingIssue
        {
            [UIHint("IssueCaretaking")]
            public KendoIssueCaretaking IssueCaretaking { get; set; }
            public int Percentage { get; set; }
        }
    }

     

  2. Peter Milchev
    Admin
    Peter Milchev avatar
    139 posts

    Posted 22 Jul Link to this post

    Hello James,

    I would suggest you to take a look at the Grid / Editing custom editor online demo which is very similar to your scenario. It will be best if you inspect it in the offline demo site, which is part of the UI for ASP.NET MVC installer.

    As mentioned in the Kendo UI for ASP.NET MVC Fundamentals article when you use strongly typed html extensions (i.e. DropDownListFor), you don't need to set the .Name() explicitly, because it is filled automatically server-side. That's why I recommend removing the .Name("IssueCaretaking") of the DropDownList template:

    @(Html.Kendo().DropDownListFor(x => x) // .Name("IssueCaretaking") is removed
        .DataTextField("DisplayName")
        .DataValueField("Id")
        .DataSource(source =>
        {
            source.Read(read =>
            {
                read.Action("GetCaretakingIssueDropdown", "Elimination"); //Set the Action and Controller names.
            })
            .ServerFiltering(true); //If true, the DataSource will not filter the data on the client.
        })
        .SelectedIndex(0)
            )

    To apply the Client template to the IssueCaretaking column you could add the .ClientTemplate("#=IssueCaretaking.DisplayName#") property to the column:

    @(Html.Kendo().Grid<KendoRecordedCaretakingIssue>()
        .Name("recordedCaretakingIssuesGrid")
        .Columns(columns =>
        {
            columns.Bound(c => c.IssueCaretaking).ClientTemplate("#=IssueCaretaking.DisplayName#").Title("Caretaking Issue").Width(150);
            columns.Bound(c => c.Percentage).Title("Percentage").Width(150);
            columns.Command(command =>
            {
                command.Destroy();
                command.Edit();
            }).Width(250);
        })
            )

    In addition to the above suggestions, please review the following video, which shows how a similar scenario works on our side. I have attached the relevant files to this message. Please integrate the approach in our offline demo site and let me know how it goes.

    http://screencast.com/t/moyJ9FCA

    A couple of final notes:

    - Partial1.cshtml is placed inside the EditorTemplates folder, where ClientCategory.cshtml resides
    - obviously the Grid in the popup editor is not related to the main Grid and does not edit its items, but the focus is on the DropDownList editor
    - I recommend you to define a default value of the IssueCaretaking object in the nested Grid's Model configuration, similar to what is done in our examples
    - the DropDownList widget may not be initialized due to two reasons mainly - a JavaScript error on the page (please check the browser console) or if there already is an element with IssueCaretaking ID on tthe page. Please verify.

    Regards,
    Peter Milchev
    Telerik by Progress
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  3. Kendo UI is VS 2017 Ready
  4. James
    James avatar
    2 posts
    Member since:
    Jun 2016

    Posted 22 Jul in reply to Peter Milchev Link to this post

    Thanks Peter!

     

    I'm getting the following error

    VM529:3Uncaught ReferenceError: IssueCaretaking is not defined

     

    I have my IssueCaretaking template (ClientCategory.cshtml) in the Shared/EditorTemplates/IssueCaretaking.cshtml path.  Is that correct?

  5. Peter Milchev
    Admin
    Peter Milchev avatar
    139 posts

    Posted 26 Jul Link to this post

    Hello James,

    The Editor templates should be in the Views/Shared/EditorTemplates folder, that is correct. 

    There are some possible scenarios that could cause that error:
    • If you get the error when you are clicking the "Add New Record" button then you should set the default value in the model configuration to be an object, as in our demos. 
    • If you get the error in "Read" mode, you should insert some conditionals in the Column Template in order to handle the cases where the object is null.

    If after following the tips above you still encounter problems I would recommend you to open a support ticket and send us a fully runnable sample project or modification of our demos recreating the issue. You can find more information on preparing the sample project in the Isolating a problem in a sample project blog post.

    Regards,
    Peter Milchev
    Telerik by Progress
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
Back to Top
Kendo UI is VS 2017 Ready