We have a page that use the Grid, Filter, and DataSource components (note that this is the newer Filter component that supports more advanced features such as grouping different conditions, and not the built-in grid filtering). We're using a shared "standalone" DataSource component so it only has to be setup once and both the Grid and Filter can reference the same thing.
Everything up to this point is working fine. The data is displayed in the grid, the filter can be used to filter the results, etc. However, we're also using getOptions()/setOptions() for both the Grid and Filter components to save the user's options when leaving the page and restore them again when they return. After setOptions() is called for the Grid, the Filter component no longer filters the results in the Grid. There aren't any errors or anything, but adding a filter that should change the results has no impact.
I'm guessing the problem is that setOptions() is changing the data source of the grid, so the Filter component is still applying the filter to the original data source, but that's no longer the same instance that the Grid component is using to display data. I tested this theory by getting a reference to the grid's original data source before calling setOptions(), then setting the grid's data source back to the original data source after calling setOptions(). Although this did fix the problem and I could apply new filters even after calling setOptions(), it also caused some other issues (ex. any previously-saved options related to the data source were now overwritten by replacing the original data source).
Is there a "right" way to do what I'm trying to accomplish here, or maybe some workaround? Is this a bug that I'm running into and it shouldn't really be this difficult? We basically just want to define a data source once, have a Filter and Grid component both reference that data source, and have everything continue to work after calling setOptions().
9 Answers, 1 is accepted
Hi, Aaron,
The Grid setOptions() method should not affect the dataSource instance, unless it is passed as one of the options that need to be replaced.
I tested the shared data source scenario and was not able to replicate the erroneous behaviour so perhaps I may have missed something.
Would you take a look and let me know of anything I may have missed?
Look forward to hearing back from you.
Kind Regards,
Alex Hajigeorgieva
Progress Telerik
Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.
Thanks for checking this out! I looked at your example and the key difference appears to be that your call to setOptions() is only setting one particular option, where in my case I'm calling getOptions() then later sending the result into setOptions().
I was able to reproduce the problem by updating useSetOptions():
function
useSetOptions() {
var
grid = $(
"#grid"
).data(
"kendoGrid"
);
var
options = grid.getOptions();
grid.setOptions(options);
}
Calling getOptions() and setOptions() back to back like this might be a little pointless, but this is just for testing purposes. In reality, we're calling getOptions() and persisting the grid options, then later calling setOptions() to restore the options. I've attached your code updated with these changes for reference.
Hi, Aaron,
Thank you very much for the provided updated project that illustrates the issue.
The reason for this behaviour is the getOptions() method. It removes the reference between the original data source and the grid. Here is a simple test that demonstrates this:
var grid = $("#grid").data("kendoGrid");
console.log("Actual options - is dataSource the same reference", grid.dataSource === dataSource1)
var options = grid.getOptions();
console.log("From getOptions() method - is dataSource the same reference", options.dataSource === dataSource1)
So in summary, the approach would be to assign the shared dataSource instance by its name before using the setOptions() method as you mentioned in your original post. I will log a task for the team to update the getOptions() method API with a note that describes this behaviour:
@(Html.Kendo().DataSource<FilterTest.Models.OrderViewModel>()
.Name("dataSource1") // use the name as a variable to restore the reference
.Ajax(d=>d.Read(r => r.Action("Orders_Read", "Grid")))
)
options.dataSource = dataSource1;
grid.setOptions(options);
As a token of appreciation for helping us improve, I have added some Telerik points to your account
Kind Regards,
Alex Hajigeorgieva
Progress Telerik
Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.
Thanks for the response, passing this on to the team, and the points! Is there a GitHub issue or Feedback Portal report for this that I should watch for future updates?
Regarding the proposed workaround (assigning the shared data source to the options before calling setOptions()), I tested this and got some mixed results, but after playing around with it I think I know why. I've attached updated code with the original useSetOptions() function updated with the workaround, as well as a few extra buttons used in troubleshooting. When used with the simplified example that we've been testing with, the workaround works fine. However, when I went to test it with our real scenario (saving the options then later restoring them), it wasn't working correctly.
To reproduce the problem with the attached example code:
- Apply a filter (ex. Ship Name Contains 3)
- Notice the results are filtered as expected
- Click "Save Options" (this saves the stringified grid options in localStorage)
- Refresh the page
- Click "Restore Options" (this reads the options from localStorage, sets the data source per the suggested workaround, then calls setOptions())
- Notice your previous filter is not restored.
The simplified test that we've been working with before doesn't allow the grid that is displayed on-screen to have options different than those returned by getOptions()/setOptions() (since both are called back to back). When updated to store the settings in localStorage, then refreshing the page, this brings an issue of the workaround to light. This effectively throws out any options tied to the data source that was persisted (and that we're trying to restore) and replaces them with the options tied to the data source of the grid currently being displayed. So, for example, if I had a filter applied to a grid and I was on page two of the results, then clicked on an item (persisting the options before navigating away), the next time I return to the grid (and the persisted options are reloaded) I would no longer be on page two of the filtered results.
Hi Aaron,
Thank you for the provided sample.
Indeed the dataSource options are not persisted using the workaround. To avoid this behavior I would suggest you to also cache the options of the dataSource and when restoring the options of the grid, also restore the saved state of the dataSource.
e.g.
function saveOptions() {
var grid = $("#grid").getKendoGrid();
var options = grid.getOptions();
var dsOptions = {};
dsOptions.page = options.dataSource.page;
dsOptions.filter = options.dataSource.filter;
dsOptions.pageSize = options.dataSource.pageSize;
dsOptions.sort = options.dataSource.sort;
dsOptions.group = options.dataSource.group;
dsOptions.aggregate = options.dataSource.aggregate;
localStorage["persistedOptions"] = kendo.stringify(options);
localStorage["dsOptions"] = kendo.stringify(dsOptions);
alert("Saved");
}
function restoreOptions() {
var grid = $("#grid").getKendoGrid();
var filter = $('#filter').getKendoFilter();
var options = JSON.parse(localStorage["persistedOptions"]);
var dsOptions = JSON.parse(localStorage["dsOptions"]);
var filterOptions = dsOptions.filter;
delete dsOptions.filter;
options.dataSource = dataSource1; // PROPOSED WORKAROUND
grid.setOptions(options);
dataSource1.query(dsOptions);
filter.options.expression = filterOptions;
filter._renderMain();
filter._addExpressionTree(filter.filterModel)
filter.applyFilter();
alert("Restored");
}
For your convenience I am attaching a modified version of the provided sample. Please note that I restore the filter only through the filter widget, in order to sync its layout with the applied filters.
I hope this helps.
Regards,
Georgi
Progress Telerik
Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.
First and most importantly, Alex Hajigeorgieva stated earlier that she would "log a task for the team to update the getOptions() method API". This sounds like the problem that I'm experiencing will be corrected in a future update, is this in fact the case? Is there anything on the Feedback Portal or a GitHub Issue that I can follow for updates? If this is something that will be addressed in the relatively near future (ex. within the next year), then a workaround might not be necessary and I can just wait for the update (as long as it's not just logged as a known issue but won't be addressed for years).
Having said that, thanks for the response and workaround, Georgi! While this does successfully restore the previous filters and the Filter component remains functional after calling setOptions() on the Grid component, there appears to be an issue with pagination when enabled. If you're on page 2 of results then save the options, refresh the page, and restore the options, you'll be left at page 1. I've attached an updated version of the sample code that has pagination enabled for reference/testing.
Also, is it necessary to persist the options of the dataSource separately? Or is restoring those options through the Filter widget the important part? Originally I was already persisting the results of grid.getOptions(), and since it looks like all of the dataSource options that are being persisted separately come from the same call to getOptions(), it seems like saving them separately would be redundant (and adds some additional complexity to my "real" scenario that is more complicated than the sample code we've been working with).
Hello, Aaron,
I have logged a task for the team to update the getOptions() method API with a note that describes the behaviour. I meant that the current behaviour needs to be documented. I did not intend to imply that this is a bug that needs to be fixed.
Currently, most of the team is away for the holiday season, however, I can address the question of whether we intend to change the behaviour in future releases at the beginning of next year.
Regarding the page, it seems to occur when the applyFilter() method is called. I debugged the suggestion and was able to simplify it and improve it in such way that the state is restored for both the filter and the grid, including the page:
function saveOptions() {
var grid = $("#grid").getKendoGrid();
var options = grid.getOptions();
localStorage["persistedOptions"] = kendo.stringify(options);
localStorage["dsQuery"] = kendo.stringify({
filter: dataSource1.filter(),
page: dataSource1.page(),
pageSize: dataSource1.pageSize(),
aggregate: dataSource1.aggregate(),
sort: dataSource1.sort(),
group: dataSource1.group()
});
alert("Saved");
}
function restoreOptions() {
var grid = $("#grid").getKendoGrid();
var filter = $('#filter').getKendoFilter();
var options = JSON.parse(localStorage["persistedOptions"]);
var dsQuery = JSON.parse(localStorage["dsQuery"]);
dataSource1.query(dsQuery);
options.dataSource = dataSource1; // PROPOSED WORKAROUND
grid.setOptions(options);
filter.setOptions({
expression: dataSource1.filter()
});
alert("Restored");
}
Steps to test:
- Using the Filter control, add "ShipName contains 2"
- Click "Apply"
- Go to page 2 in the grid
- Click "Save Options"
- Refresh the page
- Click "Restore Options"
Finally, for the question of whether we need to save the data source options - if we want to persist the data source query - page, filter, group, sort, etc. then yes, we need to save the options that we want to use as with the current behaviour they disappear.
I hope this helps.
Regards,
Alex Hajigeorgieva
Progress Telerik
Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.
Hi, Aaron,
Just a quick note to let you know that I have discussed this with the team and indeed, the behaviour of the getOptions() method will be documented but it will not be changed.
We will add an important note that describes that the dataSource options are saved but a reference to the original dataSource instance is removed.
Kind
Regards,
Alex Hajigeorgieva
Progress Telerik
Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.
Hi Alex,
Thanks for the clarification, updated code, and updates! When you originally said you "logged a task for the team with a note that describes the behavior", I thought you meant you logged a task for them to look into why it's doing this, and the "note" was so they knew what they were looking for. Now I see what you're saying, though... the task was to add better documentation regarding how this is handled (and not to change the current functionality). Thanks for clarifying, now I know I shouldn't wait for this to be changed in an upcoming update :)
Sorry for the delay in getting back to this, but as far as the most recent code suggestion, I tried it out in my "real scenario" that is a bit more complex and so far it seems to be working well. The settings are getting persisted, reloading the page successfully reapplies the sorting/filtering options as well as the correct page number of results, and the Filter component is still functional after the persisted options have been reloaded and reapplied. I think that covers everything I've ran into while troubleshooting this, so it looks like we can put this one to bed :) Thanks again for all of the help!