1

I've seen similar topics about it, but none of them using exactly the same structure as me.

I am using multiple view models and I deal with it by creating a MasterModel function which later on I pass as an argument to applyBindings.

Basically something like this:

var MasterModel = function(){
    this.user = new UserViewModel();
    this.department = new DepartmentViewModel();
}

ko.applyBindings(MasterModel);

Now, I would like to be able to access from Javascript to a function inside one of my view models and I'm having troubles with it.

I managed to call the viewmodel function if I change the applyBindings to this:

var mm = new MasterModel();
ko.applyBindings(mm);

mm.user.sayHi();

But then I found out things like the following stop working:

<ul data-bind="foreach: department.list()">
     <li data-bind="text: department.getDemo($data)"></li>
</ul>

Message: department is not defined

Reproduction online

And as you can see here, it works perfectly when using ko.applyBindings(MasterModel);

Any solution for this?

Community
  • 1
  • 1
Alvaro
  • 40,778
  • 30
  • 164
  • 336
  • to make view cleaner use `with` in such cases . very helpful – super cool Jul 15 '15 at 11:58
  • That doesn't solve much when you are inside nested elements like `foreach` – Alvaro Jul 15 '15 at 12:14
  • humm i believe you misunderstood what i am saying . check this http://jsfiddle.net/qWmat/111/ . i am just trying to say use `with` not to replace in place of `foreach` . cheers – super cool Jul 15 '15 at 12:19

2 Answers2

2

You need to point Knockout in the right direction in order to use department:

<li data-bind="text: $root.department.getDemo($data)"></li>

When you're inside a foreach loop, the scope is the item you're currently iterating on, and this item (obviously) doesn't have the department property.

You need to use $root to tell Knockout that it's the department defined on the root view-model you're referring to.

See Fiddle and Documentation

haim770
  • 48,394
  • 7
  • 105
  • 133
  • What about `$parent`? Why can't I use it? – Alvaro Jul 15 '15 at 12:12
  • In your particular case, you can use `$parent` as well. But, if you'll ever refactor your model to have more than one level of nesting `$parent` would break. You better use `$root` since you already know it's defined at the root of your view-model. – haim770 Jul 15 '15 at 12:14
  • The bad thing of it is that it starts to look very verbose. The `$parent` doesn't work at all btw: http://jsfiddle.net/imac/qWmat/112/ – Alvaro Jul 15 '15 at 13:56
  • @Alvaro `$parent` will work check the comment to you post . cheers – super cool Jul 15 '15 at 14:43
1

Inside the foreach, you don't have direct access to department because foreach introduces its own binding context. You can use $root or $parent to access your MasterModel:

<ul data-bind="foreach: department.list()">
   <li data-bind="text: $parent.department.getDemo($data)"></li>
</ul>

http://jsfiddle.net/qWmat/109/

A binding context is an object that holds data that you can reference from your bindings. While applying bindings, Knockout automatically creates and manages a hierarchy of binding contexts. The root level of the hierarchy refers to the viewModel parameter you supplied to ko.applyBindings(viewModel). Then, each time you use a control flow binding such as with or foreach, that creates a child binding context that refers to the nested view model data.

Read more

sroes
  • 14,663
  • 1
  • 53
  • 72
  • I don't understand why you have to use `$parent.department.getDemo($data)` instead of just `$parent.getDemo($data)` as you are already inside a department loop. – Alvaro Jul 15 '15 at 12:02
  • You're not inside a department loop, you're looping over the list. – sroes Jul 15 '15 at 12:16