kendo-uikendo-listview

Kendo listview - clicking elements that have been moved between listviews yields a different sender object structure


I'm seeing an issue where if I add new options to my listbox, the event.sender no longer has the same object structure when I click those newly moved options in their new listview.

I use an ajax event to bind data to the Kendo listview (this is in a method that gets triggered on document ready):

var myListBoxId = 'myListBoxHtmlId';
$.post('myUrl/myController/controllerMethod', dataToPost)
   .done(function (response, status, jqxhr) {
      $('#' + myListBoxId').kendoListBox({
          dataSource:  response.myListProperty,
          connectWith: theOtherListBoxId,
          dropSources: [theOtherListBoxId],
          toolbar: {
                        position: "right",
                        tools: ["transferAllFrom", "transferAllTo", 
                                      "transferFrom", "transferTo"]
          },
          change:  function (event) {
                myJavascriptMethod(event);
          },
          dataTextField: 'propertyNameInObjectInMyPropertyList',
          dataValueField: 'anotherPropertyNameInObjectInMyPropertyList'
  });

You can see that it binds the 'myJavascriptMethod(event)' as the change event handler.

Here is how I'm accessing the event data in myJavascriptMethod(event):

myJavascriptMethod(event){
    var selectedText = event.sender._target[0].innerHTML;
}

The problem is that if I modify the options (I'm using the 'transferFrom' and 'transferTo' to transfer options between two kendo listviews), the event.sender._target is null. I'm having difficulty figuring out what I should key onto that would work in all cases.


Solution

  • In addition to the example code above, I found this, which has more docs on listviews for .net-core:

    https://github.com/telerik/kendo-ui-core/blob/master/docs/api/javascript/ui/listbox.md

    When changing the return object in the C# List I was binding the datasource to in the response to the AJAX method, I also noticed that it doesn't really matter what type it is, as long as the property names match the listview's dataTextField and dataValueField.

    The solution to properly getting the selected item from the listview that would work with both the originally bound options and options that have been moved between listviews was this (no changes required to the listview as shown in the question):

    //reformatted this as Javascript
    //for typescript it was of this format:
    //static myTypeScriptEvent(event){
    
    function myJavascriptEvent(event){
        //This line was the fix / is key to the question:
        var dataItem = event.sender.dataItem(event.sender.select());
    }
    

    Here's a minimum example of the AJAX method that binds the listview. Include a call to this method in the document.ready function (thingId is the id of some object that will have sub objects in a list which will then be bound to the listview). In my case, I'm using typescript, you may have to convert some of it to basic javascript as your needs require (it's pretty close, but it may need some slight changes - as indicated by the '$' characters, you'll also need to include jquery for this):

    function bindListView( id: thingId ) {
        var dataToPost = {
             id: id
        };
    
        $.post('myUrl/myController/controllerMethod', dataToPost)
        .done(function (response, status, jqxhr) {
           $('#' + myListBoxId').kendoListBox({
              dataSource:  response.myList,
              connectWith: theOtherListBoxId,
              dropSources: [theOtherListBoxId],
              toolbar: {
                            position: "right",
                            tools: ["transferAllFrom", "transferAllTo", 
                                          "transferFrom", "transferTo"]
              },
              change:  function (event) {
                    myJavascriptMethod(event);
              },
              dataTextField: 'Id',
              dataValueField: 'Name'
           });  //end of listView bind
          }); //end of $.post().done() function
    }  //end of bindListView() function
    

    And finally, here's what your controller method should be like for the above: I'll include a pseudo class and fill it with data. The return object is the "response" variable, and whatever your list names are is accessed like this in the datasource: response.listname. Finally, whatever the object types are in those lists, the property names on those objects just have to match the dataTextField and dataValueField of the listview.

    //This will be the type of object I'm putting into the list that's 
    //going into the object I'm returning
    
    public MyClass {
        public int Id {get; set;}  //so we change the listview's dataValueField to Id
        public string Name {get; set;} //we change the listview's dataTextField to Name
    }
    
    //And this will be the overall type of object that will hold the list, will get
    //returned, becoming the "response" in the AJAX .done:
    public class MyReturnObject {
        public List MyList {get; set;}  //so we change the ListView's datasource to response.MyList
        //It may become myList, so you may need to look at the response object in the debugger.
    }
    
    
    [HttpPost]
    public JsonResult MyControllerMethod(int id)
    {
        //Create the return object, give it a new list, add things to the list
        //so the ListView can be bound:
        var myReturnObject = new MyReturnObject();
        myReturnObject.Mylist = new List();
        var object1 = new MyClass { Id = 1, Name = "Hello World" };
        var object2 = new MyClass { Id = 2, Name = "Hello again" };
        myReturnObject.MyList.Add(object1);
        myReturnObject.MyList.Add(object2);
    
        //Convert the return object and everything in it to Json and return it to
        //The AJAX method:
        return Json(myReturnObject);
    }