maciejka
maciejka

Reputation: 948

Bind complex model in knockout JS

I have the following JSON complex object.

{"User":
    {
    "$id":"2",
    "Id":0,
    "FirstName":null,
    "LastName":null,
    "Email":null,
    "EmailConfirmed":false,
    "PasswordHash":null,
    }
}

How to bind this object in knockout js. So far I have used somethind like this to bind property with input field.

<input required class="form-control" data-bind="value: User.FirstName" type="text" />

Functions bo build model in knockout.

function userModel() {
        var self = this;
        self.User = ko.observable();
    }

    function bindData(data) {
        userInfo.User(data["User"]);
    }

When I call submiting via JS.

var jsonData = ko.toJSON(userInfo);

Object jsonData show that property like FirstName is null, however in formular value has been written. Object userInfo stores written values in formular, I have checked it.

Should it look like this?

function userModel() {
        var self = this;
        self.Password = ko.observable();
        self.User = ko.observable();
    }

    function UserViewModel(user) {
        this.FirstName = ko.observable(user.FirstName);
        this.LastName = ko.observable(user.LastName);
        // other properties
    }

    function bindData(data) {
        userInfo.Password(data["Password"]);
        userInfo.User(new UserViewModel(data["User"]));
    }

$(document).ready(function () {
        userInfo = new userModel();
        createUser();
        ko.applyBindings(userInfo);
    });

Upvotes: 0

Views: 366

Answers (1)

Henrique Campos
Henrique Campos

Reputation: 561

For two way binding to work, you need to build the same hierarchy of observable values on the view model.

Alternatively, you could use the mapping plugin:

Since User is also a observable, you have to update your binding like so:

<input required class="form-control" data-bind="value: User().FirstName" type="text" />

Since User has a lot of properties, you could benefit from the with binding:

Here's a fiddle with both examples (with and without the parent binding)

var data = {
  "User": {
    "$id": "2",
    "Id": 0,
    "FirstName": "Joseph",
    "LastName": "Campbell",
    "Email": null,
    "EmailConfirmed": false,
    "PasswordHash": null,
  }
}

function UserViewModel(user) {
  this.FirstName = ko.observable(user.FirstName);
  this.LastName = ko.observable(user.LastName);
  // other properties
}

function bindData(data) {
  userInfo.User(new UserViewModel(data["User"]));
}

function userModel() {
  var self = this;
  self.User = ko.observable();
}

var userInfo = new userModel();
bindData(data);

ko.applyBindings(userInfo);
input {
  display: block;
  margin: 5px 0;
}

input[readonly] {
  border: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

<form data-bind="with: User">
  <input type="text" data-bind="value: FirstName" />
  <input type="text" data-bind="value: LastName" />
</form>

Current values:
<input type="text" readonly data-bind="value: User().FirstName" />
<input type="text" readonly data-bind="value: User().LastName" />

Upvotes: 1

Related Questions