solefald
solefald

Reputation: 1799

KnockoutJS: Help me organize multiple viewModels

I am having hell of a time organizing my JS file with multiple viewModels. It is a complete mess and I keep getting errors about binding multiple times, despite having read and tried every trick possible.

Here is my situation: I have 3 view models. 2 of them make ajax request on load. I have also added the stopBinding handler so i can bind multiple viewModels in the same page. It works... somewhat. I would also like to figure a way to share functions between viewModels. isDirty() in particular (described here: http://www.knockmeout.net/2011/05/creating-smart-dirty-flag-in-knockoutjs.html)

My file is quiet large, so I will post an example. Everything was implemented according to http://www.knockmeout.net/2012/05/quick-tip-skip-binding.html

JS

ko.bindingHandlers.stopBinding = {
    init: function() {
        return { controlsDescendantBindings: true };
    }
};
ko.virtualElements.allowedBindings.stopBinding = true;

// viewModelOne
$.getJSON('/admin/getusers.json', function(json, status) {

    var viewModelOne = ko.mapping.fromJS(json);

    // MODE CODE AND FUNCTIONS HERE. SOME OF THEM ARE 
    // THE SAME AS viewModelTwo USES

   ko.applyBindings(viewModelOne, $('#users-section')[0])

});


// viewModelTwo
$.getJSON('/admin/getdeployments.json', function(json, status) {

    var viewModelTwo = ko.mapping.fromJS(json);

    // MODE CODE AND FUNCTIONS HERE. SOME OF THEM ARE 
    // THE SAME AS viewModelOne USES

    ko.applyBindings(viewModelTwo, $('#deployments-section')[0])

});


// viewModelThree
var viewModelThree = {
    someFunction: function() {
       // SOME CODE HERE
    }

}
ko.applyBindings(viewModelThree, $('#logs-section')[0]);

HTML

<section>

    <!-- ko stopBinding: true -->
    <div id="deployments-section">
         // HTML HERE
    </div>
    <!-- /ko -->

    <!-- ko stopBinding: true -->
    <div id="users-section">
        // HTML HERE
    </div>
    <!-- /ko -->

    <!-- ko stopBinding: true -->
    <div id="logs-section">
        // HTML HERE
    </div>
    <!-- /ko -->

</section>
  1. I do not really need the viewModelTwo (the user.json data) to load on initial load, just when i click on a particular link, so the only data I need right away is viewModelOne (getdeployments.json data).

  2. I would like to share some functions between viewModels

  3. For some strange reason things break if i do ko.applyBindings(viewModelOne) to bind this viewModel to the entire document and remove <!-- ko stopBinding --><!-- /ko --> around <div id="deployments-section"></div>. It only works the way I posted above.

  4. I get an error about multiple bindings here ko.applyBindings(viewModelOne, $('#users-section')[0]). Adding ko.cleanNode($('#users-section')) does not help. I only get the error from this one particular binding, but not the other two.

I guess I'm open to consolidate everything into a single viewModel, if thats a better approach

Upvotes: 0

Views: 509

Answers (1)

user1375096
user1375096

Reputation:

what about get rid of stopBinding and go back to basic.

Javascript

var vm = {
    viewModelOne: ko.observable(),
    viewModelTwo: ko.observable(),
    viewModelThree: {
        someFunction: function() { /* ... */ }
    }
};

var shared_functions = {
    func1: function() { /* use "this" pointer as if it's object viewModelOne or viewModelTwo */ },
    func2: function() {}
};

ko.applyBindings(vm);

// viewModelOne
$.getJSON('/admin/getusers.json', function(json, status) {
    var viewModelOne = ko.mapping.fromJS(json);

    // MODE CODE AND FUNCTIONS HERE.

    // add shared functions too
    $.extend(viewModelOne, shared_functions);
    vm.viewModelOne(viewModelOne);
});

// viewModelTwo
$.getJSON('/admin/getdeployments.json', function(json, status) {

    var viewModelTwo = ko.mapping.fromJS(json);

    // MODE CODE AND FUNCTIONS HERE.

    // add shared functions too
    $.extend(viewModelTwo, shared_functions);
    vm.viewModelTwo(viewModelTwo);

});

HTML

<section>

  <div id="deployments-section" data-bind="with: viewModelTwo">
     // HTML HERE
  </div>

  <div id="users-section" data-bind="with: viewModelOne">
    // HTML HERE
  </div>

  <div id="logs-section" data-bind="with: viewModelThree">
    // HTML HERE
  </div>

</section>

If you want some framework level support, besides durandaljs (which I never tried), there is smaller http://pagerjs.com which supports me really well on middle scale knockout web apps.

Upvotes: 1

Related Questions