I recently created a little peice of functionality using Spry data to setup two lists that can swap data on the fly,

without the need for any postbacks to the server.  I've done this thing several times before, but in the past, I've done it very inefficiently.  Let me give you an example.

Let's say I'm building a list of songs to put on my mp3 player.  I start with a list of all the songs from my media library, as well as a blank list that's waiting to be filled up with songs for the play list. In the past, what I've done is create two Spry data connections to a database, one to manage the play list, and one to manage the full list of songs.

Of course, this is easy enough to do, but I wanted to make it a bit better.  For example, when selecting a song, I wanted to be able to show that the song was selected (and also make it un-selectable again).  

My past approach would have been to start with an onclick event to handle the data saving.  Once this process was complete, I would have fired a complete reload of both my datasets–when they would reload, the song I added would appear in the play list and the song I selected would now be flagged with a "IN_PLAYLIST" tag that would instruct whatever event listeners I had set up to ignore this until it was removed from the play list.

So this works, but it's horribly inefficient.  First, and most glaring, is that two full rounds to the server are made for every 1 song that is added to the playlist (or removed).  Second, and related, is that this does not take advanatage of easy DOM manipulation of these elements that could have saved some server round trips.  Third, it's just not very elegant, and makes the whole experience feel a bit disjointed.

Not satisified with this, I decided to really dig into doing this better when a similar bit of application work came around.I started by eliminating one of the server requests.  Since I'm going to do this without reloading the dataset from the database, I can load the "playlist" dataset without Spry and do it all on server.  Easy enough.  

So now I'm down to one dataset for my "current library".  In the code, I'm passing some information from my query about each song in the "current library," and each song that is in the playlist is marked with a boolean in a column labeled "IN_PLAYLIST".  In my HTML, I'm using a spry:if to evaluate this column, which determines what kind of image shows up next to the song (e.g., whether or not it is selectable).

From here, I'm using some standard JS to transfer all the details of the selected song to the playlist dataset.  Additionally, I'm using JS to manipulate the "selected" element so that it is no longer selected AND gives an indication that it is somehow different from the rest of the "current library" in that it is "in" the playlist dataset. Again, easy enough.

It's at right about this time that I run smack into a huge problem.  You see, all this time I've been using a Spry dataset for the "current library" songs, but I've also been paging these using SpryPagedView.js.  For some reason, even after modifying the newly selected elements through JS, if I navigate between the pages of the paged view dataset, all of the changes I make (well, at least those that are related to the spry:if) are reverted to their original form (e.g., what they looked like when I initially loaded the page).  So what's happening?  
Well, first of all, I apologize if I don't get this 100% right in my explanation, but you'll see how my understanding eventually led to a solution.

When a paged view dataset is created, all of the initial data elements are stored in various arrays.  When you navigate between pages, Spry evaluates each 'page' based on a few variables (page size, page number, etc) and uses the result to go back to these arrays and populate the data shown based on these.  Note especially that this happens every time a page in the paged view is selected.

This means that if you have a spry:if in your code, Spry runs over that for EVERY PAGE of the paged view, and does it EVERY TIME you navigate between pages.

Of course, this answers the question of what was happening to my code above.  Even though I was modifying the HTML elements of the "current library" to display based on selections, Spry didn't care what I had done once I changed the "page" of the paged view.  Rather, Spry re-evaluated the spry:if's, and re-rendered the element based on that.  Whatever parts of my changes that were in conflict with the spry:if were overwritten.

So obviously, simply modifying the HTML element itself is not enough to achieve the desired functionality. 

But never fear, for the solution is actually pretty simple. All we have to do in addition to modifying the HTML element is to also modify the array from which Spry is pulling its data each time.  As I mentioned, this is surprising simple to do.

For paged datasets, Spry stores the data items in an object called "unfilteredData".  So if my paged recordset is "pvRecords", the path in the DOM to the unfiltered data is simply "pvRecords.unfilteredData".  Now that I've accessed the array, I can search through the data items in it to find the one I want and modify it to the updated value.  Now, when

Spry evaluates the spry:if in the code, it uses the new value updated in the unfilteredData array, and renders correctly.

Here's an example of what I've done:

function modifySpryDataReference(title,dir) {

    var uds    = pvRecordsAlt.unfilteredData;
    for(i=0;i<uds.length;i++) {
        if(uds[i].TITLE == title) {
            uds[i].IN_PLAYLIST=dir;
        }
    }
}

In this example, I simply loop over the contents of the unfiltered dataset, looking for the item whose title matches the argument I pass to the function.  If a match is found, I access the "IN_PLAYLIST" item and change the boolean to whichever "direction" I'm going (e.g., whether I'm adding or removing a song from the playlist).  

So yeah, it's not too bad of a thing to do, and it helps to give a little better perspective/understanding on what Spry is doing under the covers 🙂