I am trying to get Knockout js working with jQueryMobile and am hitting a few problems when moving between pages.
I would like to try and keep the page transitions in JQM and therefore I would like to use either the multiple page option (multiple pages defined in one html file) or load the additional pages into the DOM as detailed in default AJAX behaviour section of the documentation.
JQM Page Transition Documentation
I have two individual Knockoutjs pages working both with a separate view model on each. Both pages work perfectly until I attempt to link them together through JQM.
Whichever page I attempt to load I get an error relating to a mapping on the other page. I can only assume that both pages are loaded into the single DOM and when Knockout applies the bindings it is looking for properties that do not exist.
I have attempted to make a jsFiddle to demonstrate this.
JQM - Knockout Fiddle
I am new to both JQM and Knockout so any help appreciated. If I am taking completely the wrong approach then I would appreciate someone pointing me in the right direction.
Would I be better attempting to use one ViewModel for the whole site? If not how can I use Knockoutjs with JQM?
Binding Multiple ViewModels Whether you are simply looking to keep your ViewModels nice and clean, or you have a shared ViewModel that appears on each page, there will come a time when you wish to bind multiple ViewModels on a single page. Knockout makes this quite easy.
Knockout is a JavaScript library that helps you to create rich, responsive display and editor user interfaces with a clean underlying data model.
Activating Knockout To activate Knockout, add the following line to a <script> block: ko. applyBindings(myViewModel); You can either put the script block at the bottom of your HTML document, or you can put it at the top and wrap the contents in a DOM-ready handler such as jQuery's $ function.
One "master" view model for the whole site would be acceptable. Then, you could do something like this:
var masterViewModel = {
viewModelOne: ...,
viewModelTwo: ...
}
Alternately, you can call the .applyBindings overload to apply bindings to individual elements, rather than the whole DOM:
ko.applyBindings(new modelOne("Test", "One"), $("#one")[0]);
ko.applyBindings(new modelTwo("Test", "Two"), $("#two")[0]);
Personally, I'd recommend the second approach.
I'm currently using jQuery Mobile 1.3.1 and Knockout 2.2.1 and tried many approaches before finding a (hopefully) permanent solution to this problem. The hard part is figuring out when to apply bindings. When I used jQuery's ready function, that didn't work. I found in the jQM documentation to bind upon the pageinit event callback instead of the document ready function. However, this callback is fired off every time a page is rendered for the first time so if you have 5 jQM pages, it could be fired off 5 times and you're only supposed to apply KO bindings once.
The solution I eventually used was the following:
$(document).bind('pageinit', function (e) {
var pageId = e.target.id;
for (var i in VIEW_MODELS) {
var vm = VIEW_MODELS[i];
if (pageId == vm.View) {
ko.applyBindings(vm, document.getElementById(vm.View));
}
}
});
What this is doing is every time a jQM page is initially rendered, it searches through my view models to find the view model associated with the upcoming view and applies bindings. Since pages are only initialized the first time they are rendered, it will apply ko bindings upon that first rendering and never again.
So far this is working for me but I'd be curious to hear other people's opinions or solutions to using jQM multi-page templates with Knockout.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With