Adding ListView to EditorTemplate

9 posts, 1 answers
  1. Simon
    Simon avatar
    39 posts
    Member since:
    Mar 2016

    Posted 04 Jan 2018 Link to this post

    Using the scheduler-custom-editor project as a guide I've created a custom editor template and have added a number of fields as needed for our project. One of these is a Kendo ListView that I used in another project to retrieve a number images from a web service. This all seems to be working fine but one thing I'm stuck on is writing the filename of the clicked image to a text field on the template (see screenshot). Relevant template code is:

     

    <div class="k-edit-label">
        Image Details
    </div>
    <div class="eventimage-section k-content wide">
        <div id="listView" class="k-edit-field"></div>
        <div id="pager" class="k-pager-wrap"></div>
    </div>


    <script type="text/x-kendo-template" id="template">
        <div class="eventimage">
            <img src="http://nsccapi/eventimages/\\#= FileName \\#" alt="\\#: FileName \\# image" />
                <h3>\\#: FileName \\#</h3>
            </div>
    </script>

    <script>

    var dataSource = new kendo.data.DataSource({
        transport: {
            read: {
                url: "http://myapi/api/events/allimages",
                dataType: "jsonp"
            }
        },
        pageSize: 3
    });

    $("\\#pager").kendoPager({
        dataSource: dataSource
    });

    $("\\#listView").kendoListView({
        dataSource: dataSource,
        selectable: "single",
        @* change: onChange,*@
        template: kendo.template($("\\#template").html()),
        autoBind: false
    });

    dataSource.read(); // "read()" will fire the "change" event of the dataSource and the widget will be bound

    @* function onChange() {

    //    var data = dataSource.view(),
    //        selected = $.map(this.select(), function (item) {
    //            var sel = data[$(item).index()].FileName;
    //            $("\\#ImagePath").val(sel)
    //            return sel;
    //        });

        } *@



    </script>

     

    The ListView renders the images as expected but the change event (change: onChange) of the listview fails saying that onChange is not defined. I've commented it out in my code as shown above. #ImagePath is the id of the text field I wish to write to. Am I going about this the correct way? Should I instead handle a click event on an image and grab it's filename from the <h3> tag?

    Thanks.

     

  2. Dimitar
    Admin
    Dimitar avatar
    796 posts

    Posted 08 Jan 2018 Link to this post

    Hello Simon,

    The correct way to achieve the desired result would be to initialize and configure the ListView by using the data attributes (where attendees is a collection in the Scheduler DataSource):
    // ListView in the custom Editor
    <div class="eventimage-section k-content wide">
      <div data-role="pager" data-bind="source: attendees"></div>
      <div data-role="listView" data-bind="source: attendees" data-template="template-listview" data-change="onChange"></div>
    </div>

    The ListView template can be place outside of the Scheduler's edit template:
    <script id="event-template" type="text/x-kendo-template">
      ...
    </script>
     
    <script type="text/x-kendo-template" id="template-listview">
      <div class="eventimage">
        <img src="../content/web/foods/#= ImageID#.jpg" alt="#: ImageName# image" />
        <h3>#= data.ImageName #</h3>
      </div>
    </script>

    This way, you should be able to correctly bind the change event as follows:
    <script>
      function onChange(e) {
        console.log("lv change");
      }
           
      $(function() {
        $("#scheduler").kendoScheduler({...})
      })
    </script>


    Regards,
    Dimitar
    Progress Telerik
    Try our brand new, jQuery-free Angular components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
  3. Simon
    Simon avatar
    39 posts
    Member since:
    Mar 2016

    Posted 08 Jan 2018 in reply to Dimitar Link to this post

    Ok I see where you are going, however the images that are the datasource of the ListView are retrieved from a web service, they are not a collection on the ViewModels that are the Datasource of the Scheduler. 

    The idea is that the user chooses a single image from he ListView (hence the onClick function) to designate that as the image for the event, there isn't a collection of images for the event, just a single image:

    From my ViewModel:

        public class EventScheduleViewModel : ISchedulerEvent
        {

    ......

            [StringLength(512)]
            [Display(Name = "Event Image")]
            public string ImagePath { get; set; }

            [StringLength(100)]
            [AltTextRequired(ImageField = "ImagePath", ErrorMessage = "Image Alt Text is required when adding an image for the event.")]
            [Display(Name = "Image Alt Text")]
            public string ImageAltText { get; set; }

         ...

    }

    Are you suggesting that I make this collection of images a property of my ViewModel so that data-bind="source: attendees" becomes something like data-bind="source: eventimages"? 

  4. Answer
    Dimitar
    Admin
    Dimitar avatar
    796 posts

    Posted 10 Jan 2018 Link to this post

    Hello Simon,

    Your assumption is correct. The suggested approach would require the event images to be a collection of the Scheduler ViewModel.

    Alternatively, the same behavior can be achieved by initializing the ListView in the Scheduler's edit event as follows:
    <script>
    edit: function(e){
      var dataSource = new kendo.data.DataSource({
        transport: {
          read: {
            dataType: "jsonp"
          }
        },
        pageSize: 3
      });
                                 
      setTimeout(function() {
        $("#pager").kendoPager({
          dataSource: dataSource
        });
     
        $("#listView").kendoListView({
          dataSource: dataSource,
          selectable: "single",      
          template: kendo.template($("#template").html()),
          change: function(e) {
            console.log("ListView Change Event");
          }                   
        });             
      });                     
    }
    </script>

    Checkout the following Dojo example, where the above approach is demonstrated. With it, the change event of the ListView is executed successfully and a message is being logged in the browser console to signify this.

    Regards,
    Dimitar
    Progress Telerik
    Try our brand new, jQuery-free Angular components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
  5. Simon
    Simon avatar
    39 posts
    Member since:
    Mar 2016

    Posted 10 Jan 2018 in reply to Dimitar Link to this post

    Dimitar, thank you for the suggestion, it's working great now. I implemented it in the edit event of the Scheduler as you described, that keeps my ViewModel clean. I had been trying to manage a number of project requirements on the CustomEditorTemplate but managing things in the edit event of the Scheduler seems to be a much better approach.

    I'm guessing the use of setTimeout allows some time for the loading of the data from the web service to occur before the ListView uses it as its datasource?

    Thanks again for your help with this, great stuff.

    Simon

     

  6. Dimitar
    Admin
    Dimitar avatar
    796 posts

    Posted 11 Jan 2018 Link to this post

    Hello Simon,

    I am glad to hear that the issue is resolved successfully.

    The edit template of the Scheduler is nested inside a Kendo UI Window. The reason why the setTimeout() is needed is because the edit event of the Scheduler is triggered before the Window is opened. By using the setTimeout(), we make sure that the Window widget is opened and the ListView and Pager DOM elements are available. 

    Regards,
    Dimitar
    Progress Telerik
    Try our brand new, jQuery-free Angular components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
  7. Simon
    Simon avatar
    39 posts
    Member since:
    Mar 2016

    Posted 12 Jan 2018 in reply to Dimitar Link to this post

    Ok, still a couple of issues with this approach. When the user selects an image from the kendoListView, the change function fires and I write the filename of the selected image to the ImagePath text field on the editor template:

    ....

     

                        var data = dataSource.view(),
                            selected = $.map(this.select(), function (item) {
                                var sel = data[$(item).index()].FileName;
                              //  console.log(sel);
                                $("#ImagePath").val(sel);

    ....

     

     

    <div class="k-edit-label">
        @(Html.LabelFor(model => model.ImagePath))
    </div>
    <div data-container-for="imagepath" class="k-edit-field">
        @(Html.TextBoxFor(model => model.ImagePath, new { @class = "k-textbox", data_bind = "value:ImagePath" })) <a href="\\#" id="clearImage">Clear</a>
    </div>

     

    Problem is the Model does not get updated, and this value of the ImagePath textbox is not posted when Save is clicked. In fact if this is the only change the user makes on edit of an existing event then the Update method on the associated controller never gets called as there has not been any change to the Model. I've checked the Request.Form property in a debug session and no value is posted.

    How can I update the Model in this scenario and make sure the Update controller method is invoked? Can I update the model "manually" in the edit event of the scheduler before the form is posted?

     

    Thanks,

    Simon

     

  8. Simon
    Simon avatar
    39 posts
    Member since:
    Mar 2016

    Posted 12 Jan 2018 in reply to Simon Link to this post

    This seems to work:

     

        function scheduler_save(e) {
            e.event.ImagePath = $("#ImagePath").val();
            e.event.dirty = true;
        }

    Had to set dirty to true on the model to force an update, maybe not ideal but I can live with it.

     

  9. Dimitar
    Admin
    Dimitar avatar
    796 posts

    Posted 15 Jan 2018 Link to this post

    Hello Simon,

    In the described scenario you have adopted the correct approach to force an update by modifying the dirty flag of the event model. You can checkout the Model API Reference for additional information:


    Regards,
    Dimitar
    Progress Telerik
    Try our brand new, jQuery-free Angular components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
Back to Top