Aaron
Aaron

Reputation: 767

KnockoutJs view context seems bound to the last assigned view model

I'm using KnockoutJs to successfully manage views for a tabbed SPA. Using the technique demo'd here (http://gistpages.com/2013/06/24/multiple_models_in_view_with_knockoutjs) I split the tab functionality into it's own view in it's own file.

These views work fine in isolation. The problem I have is when the second applyBindings is called it's overwriting the first.

ko.applyBindings(new FirstViewModel, document.getElementById('first-div'));
    ko.applyBindings(new SecondViewModel, document.getElementById('second-div'));

And the HTML:

   <div data-bind="stopBinding: true">
                <div id="first-div" hidden="hidden">
                    @Html.Partial("_FirstPartial")
                </div>
   </div>
   <div data-bind="stopBinding: true">
                <div id="second-div" hidden="hidden">
                    @Html.Partial("_SecondPartial")
                </div>
   </div>

If when executing a method inside the FirstViewModel I test for 'this' the object is SecondViewModel, so I get undefined errors when referencing observables on FirstViewModel because the context is wrong.

Am I trying to do the impossible? (Several sites suggest this is easy enough to make work.)

Upvotes: 2

Views: 128

Answers (2)

Aaron
Aaron

Reputation: 767

OK, I've found the problem(s).

In short there's a UL of LI that have click data bindings to a menu view model, e.g. LoadDevices(), etc. The menu view model's LoadDevices function calls into the DevicesViewModel and runs its LoadDevices() function. When I started debugging the value of self in that latter method I could see that it was the menu view model, not the devices view model upon which I was executing LoadDevices().

After some further trial and error I found that checking the value of 'this' showed the actual devices view model object.

This got me thinking that maybe I'd defined my view model incorrectly and I went to recheck the KnockoutJs documentation. Here I saw their examples for the assignment of this, e.g.

var self = this;

Checking my view models I was making the assignment but I'd dropped the var, so self was being created globally. This it seems was the root of all my problems. Defining self with var fixed the object reference issue where 'self' referred to the menu view model. The reason it had all worked before was because everything was contained within the one view model and therefore masking the global scope of 'self'. Splitting into multiple view models exposed my bug.

After this it all came right and I'm now using separate view models for effectively each tab/page of the application.

Upvotes: 1

Martijn
Martijn

Reputation: 1459

Seems like a typo, ko.applyBindings(new FirstViewModel) should be ko.applyBindings(new FirstViewModel())

when this is not the case, The error is caused by some code you have not provided, the markup you have delivered seems ok. The stopbinding suggests that there is another viewmodel bound on the parent element. Something happening here? Or perhaps the stopBinding is not working.

You can try to do a ko.dataFor(document.getElementById('second-div')) or ko.dataFor(document.getElementById('first-div')) in a console (e.g. chrome console f12+esc), or try a document.getElementById('second-div') to check if there are not 2 elements with the id 'second-div' on the page.

Upvotes: 0

Related Questions