Question

I have a viewmodel:

define(['knockout'], function (ko) {
        var self, albumWrapper;

        albumWrapper = function () {
            self = this;

            // get album name from url parameter
            var albumName = routerWrapper.router.activeInstruction().params[0];
            self.retrieveAlbum(albumName);
        };

        albumWrapper.prototype = {
            retrieveAlbum: function (name) {
                /* do something to retrieve data */
            }
        }

        return new albumWrapper();
    });

I config route to go to this view by this url: #gallery/album/:name

But when parameter (/:name) changed by this code:

window.location.href = '#gallery/album/' + data.name();

This viewmodel just occur first time, so I cannot retrieve any new album when. I think this problem because of cache view, but I not sure. Please help me fix this. I use durandal in this case.

Was it helpful?

Solution

I don't think your problem is caching, I think it has to do with the way you setup your view model. From what I see, durandal is going to resolve your view the first time and use your code above to create the viewmodel. Returning new albumWrapper() will cause your viewmodel to be a singleton. The constructor function is only going to be called on first time and never again. You can try removing the new keyword before albumWrapper() to return the function instead of an new instance of it. This way durandal will create a new view model each time which should cause your code in the constructor to be run each time as well. Although a better way might be to use the activate function and let the module life cycle work for you. See the changes below:

define(['knockout'], function (ko) {
    var self, albumWrapper;

    albumWrapper = function () {
        var self = this;

        self.CurrentAlbum = ko.observable();
    };

    albumWrapper.prototype = {
        retrieveAlbum: function (name) {
            /* do something to retrieve data */
        },
        activate: function(name) {
            var self = this;    
            var selectedAlbum = self.retrieveAlbum(name);
            self.CurrentAlbum(selectedAlbum);
        }
    }

    return albumWrapper();
});

Now durandal should get one instance of your view but call the activate function with any route parameters each time the route is requested. Also added is an observable field called Current Album that you can bind your view elements to. Navigating away from the route does not cause the instance of the view to be removed from memory like a web page, it just sits there till the next time you navigate to the route again, more like a desktop app trading out screens. The activate function is called on every navigation and lets you setup the view for new album name on the route. Assuming the retrieveAlbum function returns an album object with properties like name, date, artist, etc, you can set that as the value of Current Album observable which will automatigically update the elements on your view. Check out the docs on routing and the view life cycle here:

http://durandaljs.com/documentation/Using-The-Router.html

http://durandaljs.com/documentation/Hooking-Lifecycle-Callbacks.html

OTHER TIPS

Posting this for others that may be looking for how to disable durandal cache.

You can set cacheViews to false like this in your module to stop caching, like this singleton module:

var vm = {};
vm.cacheViews = false;
return vm;

Or in the case of the example above:

    albumWrapper = function () {
        self = this;
        self.cacheViews = false;
        // get album name from url parameter
        var albumName = routerWrapper.router.activeInstruction().params[0];
        self.retrieveAlbum(albumName);
    };
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top