0
votes

I'm trying to do the following: (see sample in jsfiddle:http://jsfiddle.net/graphicsxp/QJK99/1/)

javascript:

var originalData = {
id: 1,
name: "Main",
 children: [ { id: 2, name: "bob" }, { id: 3, name: "ted" } ],
selectedChild:  { id: 2, name: "bob" }
};

var viewModel = ko.mapping.fromJS(originalData);

viewModel.selectChild = function(){
   var obj =  { id: 9, name: "new" };

   viewModel.selectedChild(obj);
}  

ko.applyBindings(viewModel);

HTML:

 <button data-bind="click: selectChild">click me</button>

<br/>

 <span data-bind="text: selectedChild.name"></span>

but that does not display the selectedChild property. What am I doing wrong ?

[EDIT]

I had to add parenthesis to this code:

<span data-bind="text: selectedChild().name"></span>

which is fine, but I also had to add this line of code after mapping:

viewModel.selectedChild = ko.observable(viewModel.children()[0]);

which is super annoying. Why do I need to implicitely set the property to observable ? Plus, if I don't give it a default value, it won't work. WHy ?

1
ok, I think this is because selectedChild is not observable. Can someone show me the code to make it an observable property ? - Sam

1 Answers

2
votes

You should make selectedChild a computed observable which will return the selected child. Add an observable which will keep track of what child is selected. Just keep track of the id (or whatever properties uniquely identifies a child).

var originalData = {
    id: 1,
    name: "Main",
    children: [{
        id: 2,
        name: "bob"
    }, {
        id: 3,
        name: "ted"
    }],
    selectedId: 2
};

var viewModel = ko.mapping.fromJS(originalData);
viewModel.selectedChild = ko.computed(function() {
    var selectedId = this.selectedId(),
        children = this.children();

    // get the first child that has the same id as the selectedId
    return ko.utils.arrayFirst(children, function(child) {
        return child.id() === selectedId;
    });
}, viewModel);

Then to make things easier for you displaying the selected child, use the with binding to conditionally render if a valid child is selected.

<div data-bind="with: selectedChild">
    <span data-bind="text: name"></span>
</div>

updated fiddle