finnsson / pagerjs

The Single Page Application Framework for KnockoutJS
http://pagerjs.com/
MIT License
271 stars 68 forks source link

Best practice for lazy loading view models #166

Open manzanotti opened 10 years ago

manzanotti commented 10 years ago

I've got pager.js working with a big project, and have started having a few issues that have made me question how we've got it set up. What is the best practice for lazy loading view models that need to get data from an AJAX call?

I'm not using require.js, as we prefer the versioning and automatic bundling/minification that Asp.Net gives us, but we create all the view models when the SPA is loaded, and have hooked up an onNavigate method that calls the method on the view model that gets data via an AJAX call.

Obviously, this now seems like a bad idea, as we're creating thousands of variables and functions on loading the app, so I'd like to move to the lazy loading method but the documentation is a little basic, so I'm struggling to translate it to our app.

Basically, should I create the view model when it's requested by withOnShow, and make the construction of the object make the AJAX call? If it's a bad idea to create a new one every time, then how do I make the AJAX call the second time I visit the child page using lazy loading?

CuinnWylie commented 10 years ago

I spent a long time looking into this issue as well. I was interested in the asp.net bundling tools, but in the end went for a load on demand model for the scripts and page content. However the method below should work for you regardless.

The way I currently deal with it is to load/create the view models for specific pages using withOnShow, then I use afterShow to load in the data required for the viewmodel or to refresh the data when navigating back to the page. I have a helper function for afterShow that looks at the Model for a page, checks for a shown function and runs it if found (allowing me to add a handler to afterShow at the top level).

I would be interested to hear if there is another way to do this.

manzanotti commented 10 years ago

Hmm, afterShow fires before the withOnShow method, so I don't see how I can create the view model in my withOnShow method and then make the ajax call in afterShow.

My withOnShow method now looks like this:

getViewModel = function (id) {
    return function (callback) {
        var vm = viewModels[id.toLowerCase()];
        if (!vm) {
            var vmCreator = viewModelCreators[id];
            if (vmCreator) {
                vm = vmCreator.getVM($, ko, this);
                viewModels[id.toLowerCase()] = vm;
            }
        }
        if (vm && vm.show) {
            vm.show();
        }
        callback(vm);
    };
},

So, the first time a view model is requested, it is created and cached. The second time, it is retrieved from the cache. In both cases, the show method is called (if the view model has one), which makes any AJAX calls needed.

CuinnWylie commented 10 years ago

I have added the code modification that I use in my projects for this. Feel free to take a look and hopefully @finnsson will let me know if he likes the look of what I've done here.