Sunny
Sunny

Reputation: 3295

Knockout.js: How to update property on the basis of another observable array

How i can change value of one column on the basis of another column value change.In the following code i want to update % column using marks columns value change.

HTML:

<table data-bind="foreach: users()">
  <thead class="flip-content table-head">
    <tr>

      <th align="center">Name</th>
      <th align="center">Marks</th>
      <th align="center">% out of 100</th>
    </tr>
  </thead>
  <tr >
    <td data-bind="text: $data.name()"> </td>
    <td>
      <input data-bind="value: $data.marks()" />
    </td>
    <td data-bind='text:  $data.percent()'></td>

  </tr>
</table>

SCRIPT:

var UserModel = function () {
  this.users = ko.observableArray([
    {
      id: 1,
      name: ko.observable('Bob'),
      marks: ko.observable(0),
      percent: ko.computed(function () {
        //percentage formula
      }, this)
    },
    {
      id: 2,
      name: ko.observable('Jane'),
      marks: ko.observable(0),
      percent: ko.computed(function () {
        //percentage formula
      }, this)
    }
  ]);
  this.selectedUser = ko.observable(this.users()[0]);
}
var userModel = new UserModel();
ko.applyBindings(userModel);

How i can do this.

Upvotes: 1

Views: 354

Answers (1)

user3297291
user3297291

Reputation: 23372

The easiest and most common solution is to use "class" instances rather than plain objects. These allow you to easily select the right marks value because inside the constructor, this refers to the current user.

var User = function(id, name, marks) {
  this.id = id;
  this.name = name;
  this.marks = ko.observable(marks);
  this.percent = ko.pureComputed(function() {
    return this.marks() + "%";
  }, this);
}

var UserModel = function () {
  this.users = ko.observableArray([
    new User(1, "Bob", 10),
    new User(2, "Alice", 30), 
  ]);
  this.selectedUser = ko.observable(this.users()[0]);
}
var userModel = new UserModel();
ko.applyBindings(userModel);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<table data-bind="foreach: users()">
  <thead class="flip-content table-head">
    <tr>

      <th align="center">Name</th>
      <th align="center">Marks</th>
      <th align="center">% out of 100</th>
    </tr>
  </thead>
  <tr >
    <td data-bind="text: name"> </td>
    <td>
      <input data-bind="value: marks" />
    </td>
    <td data-bind='text: percent'></td>

  </tr>
</table>

If you absolutely need to use plain objects, you can define percent's logic on your parent model and pass a reference to the current item in the view to create a computed on the fly. (I wouldn't recommend this)

var UserModel = function () {
  this.users = ko.observableArray([
    {
      id: 1,
      name: ko.observable('Bob'),
      marks: ko.observable(0)
    },
    {
      id: 2,
      name: ko.observable('Jane'),
      marks: ko.observable(0)
    }
  ]);
  
  this.selectedUser = ko.observable(this.users()[0])
};

UserModel.prototype.percentageFor = function(user) {
  return user.marks() + "%";
};

var userModel = new UserModel();
ko.applyBindings(userModel);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<table data-bind="foreach: users()">
  <thead class="flip-content table-head">
    <tr>

      <th align="center">Name</th>
      <th align="center">Marks</th>
      <th align="center">% out of 100</th>
    </tr>
  </thead>
  <tr >
    <td data-bind="text: name"> </td>
    <td>
      <input data-bind="value: marks" />
    </td>
    <td data-bind='text: $parent.percentageFor($data)'></td>

  </tr>
</table>

Upvotes: 2

Related Questions