If you're using the latest version of jQuery Mobile, you must know that nested lists have only partial support. Here's the source link.. As mentioned we'll have to use the page -> page navigation system by ourselves, so here goes.
Setup
I built up an example for this sometime back. You could adapt your code to that.
I have a json object array like this :
[
{
"name": "DC Comics",
"characters": [
"All-Star Squadron",
"Birds of Prey",
...
]
},
{
"name": "Marvel Studios",
"characters": [
"Alpha Flight",
"Avengers",
"Champions",
"Defenders",
...
]
}
....
]
So, it might be better if you have two pages, one for showing the main list aka the groups and when clicked, another page to show the sub items ie., the characters.
On page load, I'd like to show something like this :

And when one of those links are clicked, I'd like to show the stuff which is present inside characters array. Like for example, if I choose "DC Comics", the current context would be :
{
"name": "DC Comics",
"characters": [
"All-Star Squadron",
"Birds of Prey",
...
]
}
From here, I'd take out the characters property and show it out in a list in a new page. (This is what nested lists used to do, anyway). So, something like this is what is needed:

Two pages, Two ViewModels
Now to achieve this, there might be ways. But the best method would be to use multiple ViewModels, one for each page, so making it 2 and bind it when that particular page is initialised. So for a particular page,
Markup :
<div data-role="page" id="groups-page"></div>
View Model :
We'd have a seperate ViewModel:
//view model for the parent page.
var groupModel = {
//data array
groupInfo: [
{
"name": "DC Comics",
"characters": [
"All-Star Squadron",
"Birds of Prey",
...
]
},
{
"name": "Marvel Studios",
"characters": [
"Alpha Flight",
"Avengers",
"Champions",
"Defenders",
...
]
}
....
]
}
pageinit event :
And bind it in pageinit event of #group-page:
//events pertaining to Page 1 - the groups
$(document).on({
"pageinit": function () {
//apply partial binding to groups-page alone. Reason we're doing this is because only this page will be available onload
ko.applyBindings(groupModel, this);
}
}, "#groups-page");
Note that the second object in applyBindings (this) indicates the DOM element with id set to groups-page.
Similarly, you'd do the same thing for the second page, #character-page :
Markup :
<div data-role="page" id="character-page"></div>
ViewModel :
//view model for the character page - basically an empty view model to be filled with data when a link is clicked.
var characterModel = {
name: ko.observable(),
characterInfo: ko.observableArray()
}
pageinit event :
//events pertaining to Page 1 - the groups
$(document).on({
"pageinit": function () {
//apply partial binding to character-page alone.
ko.applyBindings(groupModel, this);
}
}, "#character-page");
The reason we're using observables here is because everytime something is clicked, we'd be updating the observables which will automatically change the content of the second page listview.
Populating the first page
This is how my HTML structure looks like :
<ul data-bind="foreach: groupInfo">
<li>
<a href="#">
<span data-bind="text: name"></span>
<span data-bind="text: characters.length" class="ui-li-count"></span>
</a>
</li>
</ul>
And after applyBindings() is bound only to the first page, I'd call a refresh on those listviews in the page :
//apply partial binding to groups-page alone. Reason we're doing this is because only this page will be available onload
ko.applyBindings(groupModel, this);
//refresh the listview
$("ul", this).attr("data-role", "listview").listview().listview("refresh");
This would lie in the pageinit event of the #group-page.
Click event of the groups, changePage to characters
For this, I'd use the click binding of KO on the a tag of the listview in first page:
<a href="#" data-bind="click: $root.getInfo">
<span data-bind="text: name"></span>
<span data-bind="text: characters.length" class="ui-li-count"></span>
</a>
where $root is the context in ViewModel level (see docs).
Oh wait! getInfo must be added to groupModel, the model for the first page. So the viewmodel is changed to this :
//view model for the parent page.
var groupModel = {
//data array
groupInfo: [
//groups
],
//click event to be fired when an anchor tag is clicked
getInfo: function (data, e) {
//here "data" variable gives the clicked elements' corresponding array and "e" gives the event object
//prevents defaultbehaviour of anchor tag
e.preventDefault();
//setting up the character array in View model of page 2
characterModel.characterInfo(data.characters);
//setting up name variable of ViewModel in page 2
characterModel.name(data.name);
//change the page
$.mobile.changePage("#character-page", {
transition: "slide"
});
}
}
Note that I'm populating the characterModel only now. Since the properties inside this model are observables, every time these variables are updated, DOM is also updated. The HTML of the second page is :
<ul data-bind="foreach: characterInfo">
<li data-bind="text: $data"></li>
</ul>
$data is used to get the stuff inside characterInfo, if you didn't know. When this is done, you'd have something like this :

The next step would be to refresh the listview, but not in pageinit. Reason being, pageinit is fired only once and since character-page gets updated every single time a click happens, you'd have use a pageshow or pagebeforshow method. More info here. Now the events bound to the character-page are :
//events pertaining to Page 2 - the characters
$(document).on({
"pageinit": function () {
ko.applyBindings(characterModel, this);
},
"pagebeforeshow": function () {
//refresh listview before page is shown
$("ul", this).attr("data-role", "listview").listview().listview("refresh");
}
}, "#character-page");
The above snip would refresh your styles everytime the pagebeforeshow event of "#character-page" is triggered (which is what we want) and finally give you this :

So that's it! Hope this helped :)
And, before we forget,
here's a demo.