0

I am using duraldal v2, and on one of the pages I want to switch views without re-activating the model.

To achieve this I leverage approach from v1 using compose binding with view connected to observable, changed by inline click binding in my navigation links:

    <ul class="nav nav-tabs">
        <li data-bind="css: {active:activeView() == 'view1'}"><a href="#" data-bind="click: function(){setView('view1')}">View 1</a></li>
        <li data-bind="css: {active:activeView() == 'view2'}"><a href="#" data-bind="click: function(){setView('view2')}">View 2</a></li>
        . . .
    </ul>
    <div data-bind="compose: {view: activeView, activate: true, area: 'settings', transition: 'entrance', cacheViews: true}"></div>

VM:

define(['knockout'], function (ko) {
return {
    activeView: ko.observable()
    ,setView: function(view) {
        this.activeView(view);
    }
    ,activate: function (args) {
        var self = this;
        return system.defer(function(dfd) {
            self.setView('view1');
            dfd.resolve(true);
        }).promise();
    }
    . . . 

I believe this is an awkward way, and in v2 there should be a more elegant way to do this. As far as understand, I cannot use child router, like in ko samples, because it reloads model every time.

Any ideas?

Stas Slabko
  • 506
  • 5
  • 14

1 Answers1

1

Looks fine to me.

Is it the inline functions you dislike? You could just do:

    <ul class="nav nav-tabs">
        <li data-bind="css: {active:activeView() == 'view1'}"><a href="#" data-bind="click: setView1">View 1</a></li>
        <li data-bind="css: {active:activeView() == 'view2'}"><a href="#" data-bind="click: setView2">View 2</a></li>
        . . .
    </ul>

and:

return {
    activeView: ko.observable()
    ,setView1: function() { this.activeView('view1') },
    ,setView2: function() { this.activeView('view2') },
...

If this functionality is really common for you, you might consider turning it into a widget which could potentially box up a pattern like this.

Shaun Rowan
  • 9,269
  • 4
  • 28
  • 52
  • I am looking for smth like child router, but without re-activating the model every time. So i could just use markup like that in the [ko samples](https://github.com/BlueSpire/Durandal/blob/Version-2.1.0/platforms/HTML/Samples/app/ko/index.html). As router is just a "sugar over the compose binding", it should be able to switch views while keeping model intact, like I do with *compose*. – Stas Slabko Dec 12 '13 at 09:32
  • The approach you suggested would not work well in case you have 20 views: as you can't pass parameters to a binding without inline functions, you'd have to create those 20 `setViewNN()` functions in the model. – Stas Slabko Dec 12 '13 at 09:38
  • You could just create a datastructure (viewmodel) which mimics how the router works. It would take an array of supported views and expose them as an observable collection with an "active" property or something. – Shaun Rowan Dec 12 '13 at 18:10
  • Your problem is not unlike this: http://stackoverflow.com/questions/9871477/knockout-selectable-table-rows-without-extending-the-model – Shaun Rowan Dec 12 '13 at 18:11
  • btw, an alternate syntax instead of inline function would be: data-bind="setView.bind($data, 'view1')" – Shaun Rowan Dec 12 '13 at 18:14