I have 3 routes: items/one, items/two, and items/three and they're all pointing to 'items' vm/view.
in the items.js activate function, I'm checking the url, and based on that, I'm changing a filter:
function activate(r) {
switch (r.routeInfo.url) {
case 'items/one': vm.filterType(1); break;
case 'items/two': vm.filterType(2); break;
case 'items/three': vm.filterType(3); break;
}
return init(); //returns a promise
}
The items view has a menu with buttons for one, two, and three. Each button is linked to an action like this:
function clickOne() {
router.navigateTo('#/items/one');
}
function clickTwo() {
router.navigateTo('#/items/two');
}
function clickThree() {
router.navigateTo('#/items/three');
}
this all works and I get the right filter on the view. However, I've noticed that if I'm on 'one', and then go to 'two', the ko-bound variables update in 'real-time', that is, as they're changing, and before the activate promise resolves, which causes the transition to happen twice (as the data is being grabbed, and after the activate function returns).
This only happens in this scenario, where the view and viewmodel are the same as the previous one. I'm aware that this is a special case, and the router is probably handling the loading of the new route with areSameItem = true. I could split the VMs/Views into three and try to inherit from a base model, but I was hoping for a simpler solution.
I was able to solve the issue by simply removing the ko bindings before navigation using ko.cleanNode()
on the items containing div.
Assuming that in your parent view you've a reference to router.activeItem
with a transition
e.g.
<!--ko compose: {model: router.activeItem,
afterCompose: router.afterCompose,
transition: 'entrance'} -->
<!--/ko-->
then the entrance transition happens on every route you've setup to filter the current view.
But this transition should probably only happen on first time visit and from that point on only the view should be updated with the filtered data. One way to accomplish that would be to setup an observable filterType
and use filterType.subscribe
to call router.navigateTo
with the skip parameter.
Something along the line:
var filterType = ko.observable();
filterType.subscribe(function (val) {
// Create an entry in the history but don't activate the new route to prevent transition
// router plugin expects this without leading '/' dash.
router.navigateTo(location.pathname.substring(1) + '#items/' + filterType(), 'skip');
activate();
});
Please note that the router plugin expects skipRouteUrl
without leading /
slash to compare the context.path. https://github.com/BlueSpire/Durandal/blob/master/App/durandal/plugins/router.js#L402
Your experience might be different.
Last in order to support deep linking in activate
:
function activate(routerdata) {
// deep linking
if (routerdata && routerdata.filterType && (routerdata.filterType !== filterType() ) ) {
filterType(routerdata.filterType);
}
return promise;
};
来源:https://stackoverflow.com/questions/16534141/durandal-multiple-routes-one-viewmodel-view