Maintaining Index Values While Paging with Knockout.js

Printer-friendly version

Recently I was working on a project that included a grid with large amounts of data. This grid not only displayed data but also allowed the user to edit, and the saving process contains a lot of validation and behind-the-scenes adjustments to data, so the usual knockout binding wasn't always enough. In many cases, when the user updated a particular field, we wanted to default/disable/show/hide other fields within the same row. To help with this, we ended up using a custom binding handler that would add an attribute to each field with the index of the object in the observableArray.

This process was adapted from this example by Ryan Niemeyer, and looks like this: [code language="javascript"] ko.bindingHandlers.setIndex = { init: function (element, valueAccessor, allBindings, data, context) { var prop = valueAccessor(); element.setAttribute(prop, context.$index()); } }; [/code] To use this in your binding, you would add the following (with "arrayIndex" being the attribute name): [code language="html"] <input type='text' data-bind="setIndex: 'arrayIndex'" /> [/code]

Now, whenever we wanted to retrieve the index of the item in our script, we could access the value of the arrayIndex attribute. This worked awesome, until the day came where we wanted to introduce paging to the grid. To page the observableArray that was binding to the grid, I used a slightly modified (for our needs) version of this paging extender on jsFiddle.

The problem was that when I navigated to any of the pages, we'll say page three, and updated the record in row 1, when I navigated back to the first page it had actually updated data in row 1 of the first page (and the row on page three was now blank). While troubleshooting I noticed that the knockout $index() value was not actually taking pagination into consideration, and instead was only relative to the particular page that I was viewing. So rather than page one having indexes of 0-9 and page two having 10-19, each page would always only be 0-9. This wouldn't normally be an issue, except that all of our behind-the-scenes changes were happening based on the arrayIndex attribute (derived from $index()), so no matter what page you were on, you would always be updating the first page of data. To fix this, all we had to do was update our binding handler to accomodate our new paging: [code language="javascript"] ko.bindingHandlers.setIndex = { init: function (element, valueAccessor, allBindings, data, context) { var prop = valueAccessor(); //$parent.DETAIL references our observableArray element.setAttribute(prop, ((context.$parent.DETAIL.currentPage() - 1) * 10) + context.$index()); } }; [/code] With this, each page would set the arrayIndex to the correct value, and our edits once again worked properly.

Reiterating what I touched on above, this isn't normally something you would encounter unless you are making custom index-based changes, but in the event that you are, hopefully this helps prevent some of the headaches!

About the Author:

TopLine Strategies delivers the complete integration and development of sales, marketing and customer service technologies that enable corporate clientele to improve revenue streams and strengthen customer interactions. Our project management and consulting is designed to achieve timely delivery, 100 percent user adoption of the technologies we implement and deliver measurable returns on investments for our clients.

Comments (0)

Related Blogs

TheReact Native Open Source roadmap was announced in Q4 2018 after they decided to invest more in the React Native open source community.

October is not just about pumpkins, fall foliage, and cooler temps anymore. October 2018 also means the exciting introduction of Microsoft Dynamics 365 for Customer Engagement.

Back in 2016, Microsoft introduced its intentions to refresh its CRM and ERP strategy with Dynamics 365. At the heart of its services was the Common Data Model (CDM).