This is a migrated thread and some comments may be shown as answers.

Persist data source set from JavaScript

19 Answers 187 Views
MultiSelect
This is a migrated thread and some comments may be shown as answers.
Jaesoon
Top achievements
Rank 1
Jaesoon asked on 12 May 2016, 12:54 PM

I'm trying to get a multi select box to refresh it's values after selecting a value from a drop down list. I am currently using server side filtering and paging (i.e. not all items are loaded when you load the control and so scrolling will keep loading items as needed)

 

Initially the multi select is getting its data value set in the Read method like so

 

transport.Read("GetItems", "Items", new { id = @Model.Id });

At this stage, the ID parameter (from the model) it passes in is 0 and so no items are loaded in the Multi Select control.

 

I now have a drop down box with a change event attached to it. On the change event I want to refresh the data on the multi select so I do the following using JavaScript:

var multiSelect = $("#multiSelectControl").data("kendoMultiSelect");
 
multiSelect.dataSource.read({ id: value });

 

On the controller, i can see that the ID value is coming through correctly and the Multi Select loads the correct value items. (e.g. 25, 26 etc)

 

However the problem comes in when i start scrolling the multi select list. When the next items are "loading" it seems the controller is being hit again with the value from the original datasource (i.e. 0) and so removes everything from the Multi Select control.

 

How can I make it so any further reads of the data source uses the new parameter that i've set in JavaScript?

t
 
 
 
ransport.Read("GetItems", "Items", new { id = @Model.Id });
transport.Read("GetItems", "Items", new { id = @Model.Id });

19 Answers, 1 is accepted

Sort by
0
Ianko
Telerik team
answered on 14 May 2016, 01:06 PM
Hello Jaesoon,

You should rather change the options of the DataSource widget. And then just call read() with no parameters. 

For example:
var multiSelect = $("#multiSelectControl").data("kendoMultiSelect");
multiSelect.dataSource.options.transport.read.url = "/Items/GetItems/" + value;
multiSelect.dataSource.read();

The code might need to be fixed as I have tested the situation with different values, but the idea is the same. 

Regards,
Ianko
Telerik
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
0
Jaesoon
Top achievements
Rank 1
answered on 27 Jun 2016, 09:07 PM

Hi Ianko

 

Unfortunately, this does not seem to work for me as my extra parameters always comes up with the default value when the page is first loaded.

 

My controller defines the following parameters:

[DataSourceRequest] DataSourceRequest request, int objectId

 

And so i have tried 

multiSelect.dataSource.options.transport.read.url = "/Items/GetItems/" + value;

multiSelect.dataSource.options.transport.read.url = "/Items/GetItems/GetItemsList=" + value;

multiSelect.dataSource.options.transport.read.url = "/Items/GetItems?GetItemsList=" + value;

 

But the passed in extra parameter is always set to 0.

 

I can see on the network activity that the URL address is properly set but i can't get the extra parameter to pass over.

 

As mentioned in my previous post, adding the parameter in the read method (like so: multiSelect.dataSource.read({ id: value });) will pass the data back to the controller, however the problem with this is that any sort of virtualisation will mess it up. (it will pass in the default value of 0 instead of the changed value).

 

Thanks for your help.

0
Jaesoon
Top achievements
Rank 1
answered on 27 Jun 2016, 09:10 PM

Sorry, i cant edit my post, i was meant to say my javascript passes in the parameters 

multiSelect.dataSource.options.transport.read.url = "/Items/GetItems/objectId=" + value;
multiSelect.dataSource.options.transport.read.url = "/Items/GetItems?objectId=" + value;

To be what the controller needs.

 

0
Jaesoon
Top achievements
Rank 1
answered on 27 Jun 2016, 09:12 PM

Sorry I can't edit my previous post as I didn't type it properly

 

The script call i'm making is as follows:

multiSelect.dataSource.options.transport.read.url = "/Items/GetItems/objectId=" + value;
multiSelect.dataSource.options.transport.read.url = "/Items/GetItems?objectId=" + value;

 

But the parameters are still not returning properly.

0
Ianko
Telerik team
answered on 28 Jun 2016, 06:56 AM
Hello Jaesoon,

Can you provide a simple, locally runnable project that illustrates the difficulty encountered so that I can properly examine the exact situation? I suggest you using a single page solution with hard-coded values as I guess this should be a matter of a single action method to be called from the client.

Regards,
Ianko
Telerik
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
0
Jaesoon
Top achievements
Rank 1
answered on 09 Jul 2016, 12:17 AM

Hi Ianko

 

 

I have attached a zip file containing the project folder,

 

In the index.cshtml file, you will find a combobox and a multiselect control.

The multi select control has got a default parameter defined in its read method (passes in 0).

There is javascript on the file which gets hit on the combobox change event, from there you can see what the original URL is and the modified URL is.

However when it hits the read method of the controller, the parameter does not get changed (e.g. drop down has selected 3 and the URL is set to use the right link, however the read method has 0 as the parameter still).

 

Please have a look and let me know if theres anything else that's needed.

 

I have removed the bin folder (which can be recreated when you build the solution) and also the kendo folder in the content and scripts folder (so that none of the kendo files will be exposed). Please add them back to the solution before running the sample The kendo scripts folder uses version 2016.2.607.

 

Thanks

0
Ianko
Telerik team
answered on 11 Jul 2016, 07:35 AM
Hello Jaesoon,

The problem is that the .Type("aspnetmvc-ajax") is configured. This type of setting is to be be used internally for wrappers utilizing the DataSourceRequest class. MultiSelect is not among them and I can only guess why this setting is used.

With this setting, the mechanism of the request processed is different and this is why the request URL actually cannot be changed programmatically. 

You can see that if you comment out the .Type() setting in the MultiSelect and the [HttpPost] attribute for the GetItems method the request will be properly sent with the changed ID. 

Regards,
Ianko
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
0
Jaesoon
Top achievements
Rank 1
answered on 12 Jul 2016, 06:09 AM

Hi Ianko

 

 

Unfortunately that is not possible as I have read your documentation for virtualisation (and also tested it), the [.Type("aspnetmvc-ajax")] is required for the controller to send back the data, as it is using [return Json(itemsList.ToDataSourceResult(request), JsonRequestBehavior.AllowGet);]

 

Removing the HttpPost and .Type settings will cause the filter to not work at all (i.e. typing in to filter items in the multi select, opening up a control with existing values in it).

 

I have figured out another way which works partially but still has issues as shown below.

multiSelect.dataSource.transport.parameterMap = function(data, type) {
    if (type == "read") {
        return { request: kendo.stringify(data), id: 3 }
    }
};

 

By doing this, i can get the id parameter to be passed in correctly, however the [DataSourceRequest] object has all the parameters missing, which also causes issues with filtering.

 

This following method is more desirable than the one you've suggested above as at least with this one, virtualisation works when you open up this control with existing values.

 

So if I can't get your method to work without having to remove the .Type and HttpPost values, how can i return the correct DataSourceRequest object when im using the parametermap option?

 

Thanks

0
Ianko
Telerik team
answered on 13 Jul 2016, 07:23 AM
Hi Jaesoon,

You are right, in order to have the DataSource utilities like sorting, filtering and so on you should use this type of technique.

What I meant, however, is that you cannot programmatically change the DataSource instance from the client when it is of type aspnetmvc-ajax. This is because it is intended to be used internally and all options after the instance initialization are disregarded. Shortly, whatever is configured in the MVC wrapper it cannot be changed on the client by changing the options. 

The solution to your case is to actually reinitilize the entire DataSource object assigned to the multiSelect.dataSource property. And this is how you could do that:

function onChange(e) {
    var value = this.value();
 
    var multiSelect = $("#required").data("kendoMultiSelect");
     
    var newOptions = $.extend(multiSelect.dataSource.options, {
        transport: {
            read: {
                url:"/Home/GetItems/" + value
            }
        }
    });
 
    multiSelect.dataSource = new kendo.data.DataSource(newOptions);
    multiSelect.dataSource.read();
}

I hope that helps.

Regards,
Ianko
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
0
Jaesoon
Top achievements
Rank 1
answered on 13 Jul 2016, 08:05 AM

Hi Ianko

 

Sorry but as i've stated before, i HAVE to use 

return Json(items.ToDataSourceResult(request), JsonRequestBehavior.AllowGet);

[note the "ToDatSourceResult" method - which requires the control to have ".Type("aspnetmvc-ajax")" set]

 

If i do not use ToDatSourceResult, the returning object i get is NULL. Again i have to use this for the server side virtualisation of the multi select list, which can have a large number of data.

 

I have just tried your method that you have suggested, and I can see that the Json query returns data, but it does not populate the multi select list (I am guessing its due to the new data source?).

 

The only way that I have got the multi select to populate (when i have server side virtualisation enabled) to work is by modifying the parameter map as posted above.

 

I need to stress that the key point of difference here is that my multi select box has server side filtering enabled, this means:

1) using just the ".read()" operation will NOT pass in any new parameters if the controller has "HttpPost" and multi select control has ".Type" enabled (as we have found out)

2) using the ".read()" operation will NOT populate the multi select if i comment out the "HttpPost" on the controller and comment out the ".Type" enabled.

and finally

3) using the new data source options that you have suggested will NOT work, as I have virtualisation and server side filtering enabled, i.e. i need to use a custom source with parameter maps.

 

Can you show me how to modify the parameter map as i have posted previously so that it passes in the correct "DataSourceRequest" item? This is the only way that my multi select with virtualisation and server side filtering will work.

 

Thanks

0
Ianko
Telerik team
answered on 13 Jul 2016, 11:10 AM
Hello Jaesoon,

As said, with this scenario it is difficult to achieve this. Indeed, the suggested solution does not help as actually miltiselect widget disregards the new DataSource.

So, a much more complex solution would be to entirely wipe out the MultiSelect on the client and recreate a new one. Like so:
function onChange(e) {
    var value = this.value();
 
    var multiSelect = $("#required").data("kendoMultiSelect");
    var wrapper = multiSelect.wrapper;
 
    var obj = {
        "dataSource": {
            "type": "aspnetmvc-ajax",
            "transport": {
                "read": {
                    "url": "/Home/GetItems/" + value,
                    "data": function () { return kendo.ui.MultiSelect.requestData(jQuery("#required")); }
                }
            },
            "pageSize": 80,
            "page": 0,
            "total": 0,
            "serverPaging": true,
            "serverFiltering": true,
            "filter": [],
            "schema": { "data": "Data", "total": "Total" }
        }
    };
 
    var newOptions = $.extend(multiSelect.options, obj);
 
    multiSelect.destroy();
    wrapper.kendoMultiSelect(newOptions);
}
 
If you have UI issues with the widget, consider wiping out even the DOM element and create a new one. 


Basically, it is not easy to have the power of the built-in DataSource features and have the possibility to manually control the binding mechanism programmatically.

Regards,
Ianko
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
0
Jaesoon
Top achievements
Rank 1
answered on 16 Apr 2017, 08:36 AM
[quote]Ianko said:Hi Jaesoon,

You are right, in order to have the DataSource utilities like sorting, filtering and so on you should use this type of technique.

What I meant, however, is that you cannot programmatically change the DataSource instance from the client when it is of type aspnetmvc-ajax. This is because it is intended to be used internally and all options after the instance initialization are disregarded. Shortly, whatever is configured in the MVC wrapper it cannot be changed on the client by changing the options. 

The solution to your case is to actually reinitilize the entire DataSource object assigned to the multiSelect.dataSource property. And this is how you could do that:

function onChange(e) {
    var value = this.value();
 
    var multiSelect = $("#required").data("kendoMultiSelect");
     
    var newOptions = $.extend(multiSelect.dataSource.options, {
        transport: {
            read: {
                url:"/Home/GetItems/" + value
            }
        }
    });
 
    multiSelect.dataSource = new kendo.data.DataSource(newOptions);
    multiSelect.dataSource.read();
}

I hope that helps.

Regards,
Ianko
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

[/quote]

 

 

Hi Ianko

 

I've tried what you've suggested on this post, and i'm able to pass in the filters and extra parameter to the controller now.

I can see that all the values are being filtered and returned from the controller as expected.

 

However, the multi select control is not updating to show the items that's been returned.

 

Checking the network tab, i can see that there are multiple items in the Data set yet nothing shows up on the multi select control.

 

Also, while digging around the website, i came across this post: http://docs.telerik.com/aspnet-mvc/getting-started/custom-datasource#function-and-object-setup-as-datasource-objects

 

This example seems to be the perfect example of what i'm trying to achieve, yet when i try to use this with the Multi select (with virtualisation and filtering), im getting an error saying "Cannot read property 'slice' of undefined".

Is this again due to the .Type("aspnetmvc-ajax") parameter not supporting it?

 

Any idea on why 1) the multi select control is not updating with the correct data after it's passed back from the controller and 2) custom datasource data manipulation isn't working? 

 

 

Thanks

0
Ianko
Telerik team
answered on 18 Apr 2017, 06:10 AM

Hello ,

Note that if the type of the DataSource is -ajax, then the collection where all items are fetched should be in a Data field of the object returned from the request. 

The reason for the exception thrown is that there is no Data property with a collection. Therefore, when DataSource tries to read the Data  field undefined is returned on which cannot perform a slice operation. 

Therefore, you should make sure that the server response returns an object that has a Data property fetching the collection with the data items. 

Regards,
Ianko
Telerik by Progress
Try our brand new, jQuery-free Angular 2 components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
0
Jaesoon
Top achievements
Rank 1
answered on 19 Apr 2017, 12:22 PM
[quote]Ianko said:

Hello ,

Note that if the type of the DataSource is -ajax, then the collection where all items are fetched should be in a Data field of the object returned from the request. 

The reason for the exception thrown is that there is no Data property with a collection. Therefore, when DataSource tries to read the Data  field undefined is returned on which cannot perform a slice operation. 

Therefore, you should make sure that the server response returns an object that has a Data property fetching the collection with the data items. 

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

[/quote]

 

Hi Ianko

 

Thank you for your reply but it looks like you've skipped over my first question and only answered my second question.

I'd like to pursue the 1st question as it's what I need.

 

The code snippet you provided me with the onChange(e) is nearly working.

Using the below

var value = this.value();
 
var multiSelect = $("#required").data("kendoMultiSelect");
  
var newOptions = $.extend(multiSelect.dataSource.options, {
    transport: {
        read: {
            url:"/Home/GetItems/" + value
        }
    }
});
 
multiSelect.dataSource = new kendo.data.DataSource(newOptions);
multiSelect.dataSource.read();

 

brings back correct data as shown below in the network trace

{Data: [,…], Total: 265, AggregateResults: null, Errors: null}
AggregateResults
:
null
Data
:
[,…]
0
:
{ItemId: 1,…}
1
:
{ItemId: 2,…}
Errors
:
null
Total
:
265

 

Whenever theres a change to the drop down list, the data source for the multi select changes, and it returns the right data - i can see it coming back in the network tab.

 

However, the problem is, the data that gets returned is not showing on the multi select control at all.

 

My original call is below (which does not filter the multi select - but does bring back an unfiltered data list):

var value = this.value();
var multiSelect = $("#required").data("kendoMultiSelect");
 
multiSelect.dataSource.transport.parameterMap = function(data, type) {
    if (type == "read") {
        return { request: kendo.stringify(data), id: value }
    }
};

 

Also returns the same data set, but in this case, puts them into groups like below:

{Data: [,…], Total: 265, AggregateResults: null, Errors: null}
AggregateResults
:
null
Data
:
[,…]
[0 … 99]
[100 … 199]
[200 … 264]
Errors
:
null
Total
:
265

 

Looking at the controller, the two methods (your suggested and my current) returns the exact same data, yet your method is not showing the data on the multi select control.

 

The multi select control is using a custom data source - just like from the demo pages below: (dont worry about the semantics - im just trying to show you that im using a custom data source)

@(Html.Kendo().MultiSelectFor()
      .Name("orders")
      .DataTextField("ShipName")
      .DataValueField("OrderID")
      .MinLength(3)
      .HtmlAttributes(new { style = "width:100%" })
      .Template("#= OrderID # | For: #= ShipName #, #= ShipCountry #")
      .Height(290)
      .Filter(FilterType.Contains)
      .DataSource(source => {
          source.Custom()
              .ServerFiltering(true)
              .ServerPaging(true)
              .PageSize(80)
              .Type("aspnetmvc-ajax") //Set this type if you want to use DataSourceRequest and ToDataSourceResult instances
              .Transport(transport =>
              {
                  transport.Read("Virtualization_Read", "DropDownList");
              })
              .Schema(schema =>
              {
                  schema.Data("Data") //define the [data](http://docs.telerik.com/kendo-ui/api/javascript/data/datasource#configuration-schema.data) option
                        .Total("Total"); //define the [total](http://docs.telerik.com/kendo-ui/api/javascript/data/datasource#configuration-schema.total) option
              });
      })
      .Virtual(v => v.ItemHeight(26).ValueMapper("valueMapper"))

 

Can you tell me how I can make your example return the data that can be displayed on the multi select control?

0
Ianko
Telerik team
answered on 20 Apr 2017, 04:55 AM

Hello ,

Can you please provide a simple, locally runnable project with the modifications done so to be able to properly recreate the experienced difficulties and properly examine the case?

Regards,
Ianko
Telerik by Progress
Try our brand new, jQuery-free Angular 2 components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
0
Jaesoon
Top achievements
Rank 1
answered on 20 Apr 2017, 11:17 AM
[quote]Ianko said:

Hello ,

Can you please provide a simple, locally runnable project with the modifications done so to be able to properly recreate the experienced difficulties and properly examine the case?

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

[/quote]

 

Hi Ianko

 

I have created a test MVC application which reproduces my issue.

 

Please note the following to get the solution running:

I am using the code located here for drop down: http://demos.telerik.com/aspnet-mvc/dropdownlist/custom-datasource

I am using the code located here for Multi select: http://demos.telerik.com/aspnet-mvc/multiselect/virtualization

The database i'm using is NorthWind database: https://northwinddatabase.codeplex.com/

I am using Kendo version 2016.2.607.545

 

The solution uses HomeController for its data.

 

Everything you need has been set up for you already in the solution with the exception of the database which you will need to create locally.

 

Please create an ADO.net connection to the NorthWind database and name the connection to be SampleEntities.

 

The controls are hosted under Views/Home/Index.cshtml,

You will see 2 controls, a drop down list and a multi select and javascript code.

 

I have put in my original code and your code (commented out) and have written "TODO": under each one for you to easily identify.

 

Please run the solution as it is first to see the behaviour im getting now (data cant be filtered but it is showing up. and then comment my section out and comment your section in (you'll see no data shows on the multiselect, yet data is returning to the view).

 

Please only test with the first 4 items from the drop down list - you will understand why if you look at the HomeController under the GetOrders() method.

 

The solution is called Webpplication1 and the zip file is 22321kb 

 

I have hosted the file on the following link: https://ufile.io/ln689

 

Please let me know how your testing goes.

 

 

Thanks

0
Ianko
Telerik team
answered on 21 Apr 2017, 02:57 PM

Hello ,

With the first approach you have, method is called when filtering. Therefore, the filter that DataSource would send should be accommodated as well. I suggest you placing a debugger in the parameterMap handler and investigate some more during filtering. 

For the second approach, seems that setting a new DataSource instance directly does not populate data to MultiSelect. You can use the setDataSource method instead. 

var newOptions = $.extend(multiSelect.dataSource.options, {
    transport: {
        read: {
            url: '/Home/Virtualization_Read?idToGet=' + currentAccServiceType
        }
    }
});
 
multiSelect.setDataSource(new kendo.data.DataSource(newOptions));

Regards,
Ianko
Telerik by Progress
Try our brand new, jQuery-free Angular 2 components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
0
Jaesoon
Top achievements
Rank 1
answered on 21 Apr 2017, 11:40 PM
[quote]Ianko said:

Hello ,

With the first approach you have, method is called when filtering. Therefore, the filter that DataSource would send should be accommodated as well. I suggest you placing a debugger in the parameterMap handler and investigate some more during filtering. 

For the second approach, seems that setting a new DataSource instance directly does not populate data to MultiSelect. You can use the setDataSource method instead. 

var newOptions = $.extend(multiSelect.dataSource.options, {
    transport: {
        read: {
            url: '/Home/Virtualization_Read?idToGet=' + currentAccServiceType
        }
    }
});
 
multiSelect.setDataSource(new kendo.data.DataSource(newOptions));

 

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

[/quote]

 

Hi Ianko

 

Thanks for your code snippet, we're nearly there.

 

If you change the solution to use the setDataSource, the multi select is now showing the data correctly on the Multi select.

 

BUT, if you try the following, you'll get javascript errors

 

1) select an item from the drop down - multi select populates

2) type something in the multi select (e.g. type in "a" and leave it or select an item)

3) try to change the item in the drop down,

4) you'll get an error: Uncaught TypeError: Cannot read property 'item' of undefined

 

If you don't type anything in the multi select in between the drop down item changes, you won't get any errors.

 

If you put a debugger just before the "setDataSource" line, you'll see that it fails when it tries to set it with the newOptions.

 

This is probably the last hurdle for this control so heres hoping that theres a way around this.

 

How can i prevent the above error from happening?

 

Thanks

0
Ianko
Telerik team
answered on 25 Apr 2017, 06:19 AM

Hello ,

On my end, I am not experiencing the mentioned JavaScript error. Here you are the results on my end: https://www.screencast.com/t/6KtZ5rYdot. Also, I am attaching the Index. file to see if there are any differences that might be related.

Regards,
Ianko
Telerik by Progress
Try our brand new, jQuery-free Angular 2 components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
Tags
MultiSelect
Asked by
Jaesoon
Top achievements
Rank 1
Answers by
Ianko
Telerik team
Jaesoon
Top achievements
Rank 1
Share this question
or