Reputation: 707
I have a problem with the $parent in javascript knockouts.
If i have model:
var Person = function () {
var self = this;
self.person_Id = ko.observable();
self.firstName = ko.observable();
self.lastName = ko.observable();
self.age = ko.observable();
self.role = ko.observable();
self.init = function (data) {
self.person_Id(data.person_Id);
self.firstName(data.firstName);
self.lastName(data.lastName);
self.age(data.age);
self.role(data.role);
};
};
and the collection
var PersonCollection = function () {
var self = this;
self.ItemToEditOrToAdd = ko.observable(new Person());
self.persons = ko.observableArray();
self.AddItem = function (item) {
self.persons.push(item);
};
};
and the html
<div id="new" data-bind="with: PersonCollectionInstance.ItemToEditOrToAdd">
<p>Firstname: <input type="text" data-bind="value: firstName"/></p>
<p>Lastname: <input type="text" data-bind="value: lastName"/></p>
<p>Age: <input type="text" data-bind="value: age"/></p>
<p>Role: <input type="text" data-bind="value: role"/></p>
<button data-bind="click: $parent.PersonCollectionInstance.AddItem">Add new</button>
</div>
If you look at the html, the natural way to access AddItem is to write
<button data-bind="click: $parent.AddItem">Add new</button>
This doesnt work, because the $parent binding gets me to my AppVM that is my all mighty view model, instead of going back to my PersonCollectionInstance.
Thats why i need to do it like this:
<button data-bind="click: $parent.PersonCollectionInstance.AddItem">Add new</button>
Can anyone explain to me why $parent gets me back to my all mighty viewmodel instead of the PersonCollectionInstance where my AddItem is?
Upvotes: 3
Views: 1348
Reputation: 139758
You need to write data-bind="click: $parent.PersonCollectionInstance.AddItem"
because you have defined your with
like this:
data-bind="with: PersonCollectionInstance.ItemToEditOrToAdd"`
So you have stepped down two levels in your with
binding because you have accessed a nested property. However the $parent
is still pointing to your main view model because knockout isn`t able track your nested property and it doesn't create the nested contexts for you.
So can achieve the desired outcome with using two with
:
<div id="new" data-bind="with: PersonCollectionInstance">
<!-- ko with: ItemToEditOrToAdd -->
<p>Firstname: <input type="text" data-bind="value: firstName"/></p>
<p>Lastname: <input type="text" data-bind="value: lastName"/></p>
<p>Age: <input type="text" data-bind="value: age"/></p>
<p>Role: <input type="text" data-bind="value: role"/></p>
<button data-bind="click: $parent.AddItem">Add new</button>
<!-- /ko -->
</div>
And if you anyway using two with
you can put your button "outside":
<div id="new" data-bind="with: PersonCollectionInstance">
<!-- ko with: ItemToEditOrToAdd -->
<p>Firstname: <input type="text" data-bind="value: firstName"/></p>
<p>Lastname: <input type="text" data-bind="value: lastName"/></p>
<p>Age: <input type="text" data-bind="value: age"/></p>
<p>Role: <input type="text" data-bind="value: role"/></p>
<!-- /ko -->
<button data-bind="click: AddItem">Add new</button>
</div>
Upvotes: 5