Kasheftin
Kasheftin

Reputation: 9463

Using foreach binding without changing context in Knockout.js

Is it possible to use foreach binding without changing it's context?

For example, here's my template:

<div data-bind="foreach:{data:users,as:'user'}">
  <div data-bind="template:{name:'userAvatar',data:user}"></div>
</div>

<div data-bind="template:{name:'userAvatar',data:currentUser}"></div>

<script type="text/template" id="userAvatar">
  <img data-bind="attr:{src:avatarUrl}">
</script>

So I use template 'userAvatar' inside the foreach loop and outside it. And now I want to perform some action when user clicks to an avatar. For example, my model is

var MyModel = function() {
  this.users = [
    {name:"user1",avatarUrl:"url1"},
    {name:"user2",avatarUrl:"url2"}
  ];
  this.currentUser = {name:"user3",avatarUrl:"url3"};
  this.openProfile = function() {
    // opening user profile
  }
}

This case if I want to call 'openProfile' action in template I have to use $parent.openProfile when the template lies outside foreach and $parents[1].openProfile, when it's inside it.

I can copy link to openProfile to each user object or specify the location of openProfile method when I call the template binding, but is there more natural solution?

P.S. And I can't use $root variable because in real world my $root lies 10 levels upper of theese models.

Upvotes: 2

Views: 1980

Answers (2)

Michael Best
Michael Best

Reputation: 16688

My Repeat binding does a similar action as foreach, but without creating a child context.

<div data-bind="repeat:users" 
    data-repeat-bind="template:{name:'userAvatar',data:$item()}"></div>

Another option (maybe better) that applies to your example, because it uses template, is the foreach option of template:

<div data-bind="template:{name:'userAvater',foreach:users}"></div>

Upvotes: 3

Luffy
Luffy

Reputation: 2337

You can convert users array to Object and implement the click action in that object.

function User(name,avatarUrl) {
   var self = this;

   this.name = ko.observable(name);
   this.avatarUrl = ko.observable(avatarUrl);

   this.openProfile = function() {
      ....
   }
}


users = ko.observableArray([new User(...),new User(...)]);

I think that action naturally belongs to User model not your root model.

Upvotes: 0

Related Questions