Water Cooler v2
Water Cooler v2

Reputation: 33880

How to get this simple one-way binding with knockout to work?

I am learning knockout and this is my first ever example of it, so please be gentle.

I just want a one-way binding from the model to the textboxes, i.e, whatever is in the model must be displayed in the text boxes. I do not want to create observables yet.

Here is what I have, but when I run this code, the text boxes do not contain the model values, and the console reports an error:

TypeError: c is null

Here is my code:

1.html

<html>
    <head>
        <meta charset="utf-8"/>
        <script type='text/javascript' src='knockout-3.4.0.js'></script>
        <script type='text/javascript' src='1.js'></script>
    </head>

    <form id = "frm" name = "frm">
        <fieldset>
            <legend>Your friend's basic information</legend>

            <div>
                <label for = "FirstName">First Name</label>
                <input type = "text" name = "FirstName" id = "txtFirstName" data-bind = "value: friend.firstName" />
            </div>

            <div>
                <label for = "LastName">Last Name</label>
                <input type = "text" name = "LastName" id = "txtLastName" data-bind = "value: friend.lastName" />
            </div>
        </fieldset>

    </form>
</html>

1.js

var model = 
{
    friend : 
    {
        firstName : 'Sathyaish',
        lastName : 'Chakravarthy'
    }
};

ko.applyBindings(model);

It looks like knockout isn't able to bind a nested property. Since the property I am binding to isn't directly a member of the model object, but it is instead nested inside model.friend, it isn't able to bind it.

Surely it can't be that I cannot have a hierarchical model and that I can only bind if the properties are top-level members of the model object?

I am most likely doing something wrong with the syntax.

Upvotes: 0

Views: 50

Answers (2)

Fabio Silva Lima
Fabio Silva Lima

Reputation: 714

You will need to use mapping library to do that. When you use nested properties like a class you need to use mapping. check it out: Plugin Knockout Mapping

Your code wil be some like that:

var viewModel = function () {
var _vm = null,

init = function () {

    _vm = {
      friend : ko.mapping.fromJS({
        firstName : 'Sathyaish',
        lastName : 'Chakravarthy'
        }),
        change: function(){
        _vm.friend.firstName('first name changed');
        }
    };

    ko.applyBindings(_vm, $('#frm').get(0));
}

return {
    init: init
}

}();

i have that scenario all the time. I put in JSFIDDLE check it out

Upvotes: 0

Max Koretskyi
Max Koretskyi

Reputation: 105547

If you don't pass rootElement to apply bindings, it's going to use window.document.body. However, if you script is loaded in head section, the body is not available at that moment. So you need to move your 1.js loading inside the body like this:

<html>
    <head>
        <meta charset="utf-8"/>
        <script type='text/javascript' src='https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-debug.js'></script>

    </head>

    <body>
    <form id = "frm" name = "frm">
        <fieldset>
            <legend>Your friend's basic information</legend>

            <div>
                <label for = "FirstName">First Name</label>
                <input type = "text" name = "FirstName" id = "txtFirstName" data-bind = "value: friend.firstName" />
            </div>

            <div>
                <label for = "LastName">Last Name</label>
                <input type = "text" name = "LastName" id = "txtLastName" data-bind = "value: friend.lastName" />
            </div>
        </fieldset>

    </form>
    <script type='text/javascript' src='1.js'></script>
    </body>
</html>

Upvotes: 1

Related Questions