First, the jsfiddle link http://jsfiddle.net/wenbert/m5pHs/36/
<button data-bind="click: addHero">Add Hero With Meta</button>
<ul data-bind="foreach: heroes">
<li class="parent" data-bind="ifnot: isDeleted">
<input class="big-box" type="text" data-bind="value: name" />
<button class="btn-small" data-bind="click: $parent.removeHero">Remove Hero</button>
<br/>
<button class="btn-small" data-bind="click: $parent.addMeta">Add Meta</button>
<div class="child" data-bind="template: { name: 'checkbox-template' }"></div>
</li>
</ul>
<script type="text/html" id="checkbox-template">
<ul data-bind="foreach: meta">
<li data-bind="ifnot: isDeleted">
<input class="child-item blue" type="text" data-bind="value: name" />:
<input class="child-item small" type="text" data-bind="value: damage" />
<button class="btn-small" data-bind="click: $parent.removeMeta">Remove Meta</button>
<br/>
</li>
</ul>
</script>
<pre data-bind="text: ko.toJSON($data, null, 2)"></pre>
The Javascript
var initialData = [
{
name: "Batman",
isDelete: false,
meta: [
{ name: "Belt", damage: "99", isDeleted: false },
{ name: "Gun", damage: "104", isDeleted: false}
]
},
{
name: "Hulk",
isDelete: false,
meta: [
{ name: "Pants", damage: "1", isDeleted: false }
]
},
];
function Hero(data) {
var self = this;
self.name = ko.observable(data.name);
self.meta = ko.observableArray(data.meta);
self.isDeleted = ko.observable(data.isDeleted);
}
function Meta(data) {
var self = this;
self.name= ko.observable(data.name);
self.damage= ko.observable(data.damage);
self.isDeleted = ko.observable(data.isDeleted);
}
function SuperheroViewModel() {
var self = this;
self.heroes = ko.observableArray();
self.heroes.meta = ko.observableArray();
self.heroes.push(new Hero(initialData[0]));
self.heroes.push(new Hero(initialData[1]));
self.addHero = function() {
self.heroes.push(
new Hero({
name: 'Wolverine',
isDelete: false,
meta: [new Meta({name: 'Claws', damage: '200', isDeleted: false})]
})
);
/*
//Using something like this also does not enable me to update the child items when adding.
self.heroes.push(new Hero(initialData[1])
);*/
}
self.addMeta = function(item) {
item.meta.push(new Meta({name: '--', damage: '0', isDeleted: false}));
}
self.removeHero= function(item) {
item.isDeleted(true);
}
self.removeMeta = function(item) {
item.isDeleted(true);
}
}
ko.applyBindings(new SuperheroViewModel());
What it looks like

What works:
- Add a Hero
- Removing a Hero (by setting
isDeletedto true) - Adding a Meta
- Updating a Hero name updates the data in the debug view
What does not work:
- Removing a Meta – I cannot set the
meta.isDeletedto true - Meta (EG: Belt, Gun, Pants), are not update when you change the values in the textbox. But if you edit the Meta, and then edit the parent, the Meta is updated. Looks like the child items are only triggered when the parent are updated.
Gotcha
- If you add a New Hero and then edit the Meta, they are automatically updated even without updating the parent items.
So 2 questions:
- How do I set a value of a child object using what I have in my jsfiddle? http://jsfiddle.net/wenbert/m5pHs/36/
- How do I trigger an update when child items are updated? Right now, the child item update is only triggered when you also update the parent (EG: Batman, Hulk)
Update: It seems that the child items are not updated because they are added using the initialData array.
Thank you!
Ok, consider the changes in this fiddle, which works, and I think is much cleaner.
I’ll break down what I did
First, I’m passing the
datain through the viewmodels constructor, so that it is reusable:Next, construct the
heroesarray with a map, so that it will populate regardless of the size of the incoming data:I also moved the
metaconstruction into the heroes object, sincemetais a children ofheroes, and not the root viewmodel:Since the
heroconstructor handles themetaconstruction, theaddHerofunction no longer needs to, so itsmetaline looks the same as the initialData lines:Lastly, I moved the
add/removemeta functions into theheroviewmodel. This makes more sense, and it solves the scope issues of trying to use$parentfrommeta.Let me know if you have any questions.