0

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 ? Commented Mar 13, 2013 at 20:37

1 Answer 1

2

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

Sign up to request clarification or add additional context in comments.

4 Comments

thanks for helping. I need to have a selectedChild object as part of my data though. I can't just have an id. I've created a new jsfiddle that better show my problem. See there is two issues with it: 1) the length of the array does not show in the view (although it definitely changes as you can see in the alert box). 2) the selected student is not shown in the view either. Could you help me get this sample to work as it matches more closely what I'm trying to achieve ? thanks you (jsfiddle : jsfiddle.net/graphicsxp/QJK99/3 )
There you would just use the with binding like I have already shown. The problem you're seeing there is that the selectedChild is intially null. When the bindings are being applied, the selectedChild().name part breaks all bindings. By using with here, it won't cause issues. Also, take care in accessing properties like that in bindings, otherwise you'll see this breaking. Pay attention to what the console is logging, you'll see the errors I'm referring to.
yes indeed, the with was required. Now the selected student shows up. However the length of the array still don't show up. See updated jsfiddle: jsfiddle.net/graphicsxp/QJK99/5 Any idea what's missing ?
Again it's the same problem. The students array is initially null so you should use the with binding on that again. Or you could just initialize the array as empty instead of null in the originalData.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.