Then I apply a filter for movies made in Nigeria, the results would still be sorted by genre, but the order of all the movies in the same genre got mixed up:
You can see that in the original list, the Nigerian Action movies showed up in the order 43-8-4-13, but after the results were filtered, the order was 4-8-13-43. The best solution I thought to fix this would be to sort primarily by genre, and secondarily by ID. Since the ID is unique across all the rows, the order of movies that contain identical genres will stay the same.
Let's start with the some HTML and JavaScript to create the filterable grid, there are several tutorials online about how to get this far, so I won't go into any details.
<html> <head> <title>dgrid secondary filtering</title> <script data-dojo-config="async: true" src="js/dojo/dojo.js"></script> <script> require([ "dgrid/OnDemandGrid", "dojo/store/Memory", "dojo/on", "dojo/dom", "dojo/domReady!" ], function(Grid, Memory, On, Dom) { var genres = ['Comedy','Action','Drama', 'Musical','Doco']; var countries = ['Australia','USA','Japan','England','Nigeria']; var data = []; for (var i=1; i<50; i++) { var title = "Movie " + i; var genre = genres[Math.floor(Math.random() * genres.length)]; var country = countries[Math.floor(Math.random() * countries.length)]; data.push({id:i, title:title, genre:genre, country:country}); } store = new Memory({ data: data }); grid = new Grid({ store: store, query: filterData, columns: {id:"ID",title:"Title",genre:"Genre",country:"Country"} }, "grid"); grid.set('sort', [ { attribute : 'genre', descending : false }, { attribute : 'id', descending : false } ]); On(Dom.byId("country-select"), "change", function(evt) { grid.refresh(); }); On(Dom.byId("genre-select"), "change", function(evt) { grid.refresh(); }); function filterData(item, index, items) { var countrySel = Dom.byId("country-select"); var country = countrySel.options[countrySel.selectedIndex].value; var genreSel = Dom.byId("genre-select"); var genre = genreSel.options[genreSel.selectedIndex].value; return (!country || country == item.country) && (!genre || genre == item.genre); } }); </script> <style> body { font-family: sans-serif; font-size: 11px; } .claro .ui-state-default.dgrid-row-odd { background: #EEE; } </style> </head> <body class="claro"> <div> <label for="genre-select">Genre:</label> <select id="genre-select"> <option value="">All</option> <option value="Comedy">Comedy</option> <option value="Action">Action</option> <option value="Drama">Drama</option> <option value="Musical">Musical</option> <option value="Doco">Doco</option> </select> <label for="country-select">Country:</label> <select id="country-select"> <option value="">All</option> <option value="Australia">Australia</option> <option value="England">England</option> <option value="India">India</option> <option value="Japan">Japan</option> <option value="Nigeria">Nigeria</option> <option value="USA">USA</option> </select> </div> <div id="grid"> </div> </body> </html>
Although it's not too easy to find in the API, it is possible to sort a grid by multiple columns. For example, we could add this code to set up a default sort which would use a secondary sort on ID to retain the order of rows after filtering:
grid.set('sort', [ { attribute : 'genre', descending : false }, { attribute : 'id', descending : false } ]);
This works for the default sort, but if we try to sort by country and filter by genre, we run into the same problems. Luckily, dgrid allows you to intercept the sort event and override it with your own implementation by using:
grid.on("dgrid-sort", onSort);
We can then prevent the usual sort for happening by calling preventDefault/stopPropagation on the event passed to our sort function, and then use the sort information from the event, but add our own secondary sort option:
function onSort(event) { // Stop the normal sort event/bubbling event.preventDefault(); event.stopPropagation(); updateSort(event.sort[0]); } function updateSort(sortType) { // Always sort secondarily by ID so that a definite order is kept grid.set('sort', [ sortType, { attribute : 'id', descending : false } ]); }
And there you go, sort order maintained, mission accomplished!
Here is the full code:
<html> <head> <title>dgrid secondary filtering</title> <script data-dojo-config="async: true" src="js/dojo/dojo.js"></script> <script> require([ "dgrid/OnDemandGrid", "dojo/store/Memory", "dojo/on", "dojo/dom", "dojo/domReady!" ], function(Grid, Memory, On, Dom) { var genres = ['Comedy','Action','Drama', 'Musical','Doco']; var countries = ['Australia','USA','Japan','England','Nigeria']; var data = []; for (var i=1; i<50; i++) { var title = "Movie " + i; var genre = genres[Math.floor(Math.random() * genres.length)]; var country = countries[Math.floor(Math.random() * countries.length)]; data.push({id:i, title:title, genre:genre, country:country}); } store = new Memory({ data: data }); grid = new Grid({ store: store, query: filterData, columns: {id:"ID",title:"Title",genre:"Genre",country:"Country"} }, "grid"); grid.on("dgrid-sort", onSort); updateSort({ attribute : 'genre', descending : false }); On(Dom.byId("country-select"), "change", function(evt) { grid.refresh(); }); On(Dom.byId("genre-select"), "change", function(evt) { grid.refresh(); }); function filterData(item, index, items) { var countrySel = Dom.byId("country-select"); var country = countrySel.options[countrySel.selectedIndex].value; var genreSel = Dom.byId("genre-select"); var genre = genreSel.options[genreSel.selectedIndex].value; return (!country || country == item.country) && (!genre || genre == item.genre); } function onSort(event) { // Stop the normal sort event/bubbling event.preventDefault(); event.stopPropagation(); updateSort(event.sort[0]); } function updateSort(sortType) { // Always sort secondarily by ID so that a definite order is kept grid.set('sort', [ sortType, { attribute : 'id', descending : false } ]); } }); </script> <style> body { font-family: sans-serif; font-size: 11px; } .claro .ui-state-default.dgrid-row-odd { background: #EEE; } </style> </head> <body class="claro"> <div> <label for="genre-select">Genre:</label> <select id="genre-select"> <option value="">All</option> <option value="Comedy">Comedy</option> <option value="Action">Action</option> <option value="Drama">Drama</option> <option value="Musical">Musical</option> <option value="Doco">Doco</option> </select> <label for="country-select">Country:</label> <select id="country-select"> <option value="">All</option> <option value="Australia">Australia</option> <option value="England">England</option> <option value="India">India</option> <option value="Japan">Japan</option> <option value="Nigeria">Nigeria</option> <option value="USA">USA</option> </select> </div> <div id="grid"> </div> </body> </html>