可观察的数组值更新

时间:2016-07-22 09:33:04

标签: arrays knockout.js

对于时间表应用程序,我有一个可观察的数组:

DayHrs

DayHrs包含5天或7天,具体取决于员工。 我有一个WeekHrs,这是一个计算字段。

当用户输入其中一个DayHrs的值时,我希望HKH的总字段立即更新。

所以在我的数据绑定中我想使用valueUpdate:' afterkeydown'。

但是我无法将其作为计算字段,因为可观察数组中的数组项本身不可观察。

根据Knockout文档:关键点:observableArray跟踪数组中的对象,而不是这些对象的状态。

那么我该如何解决这个问题呢?有没有办法迭代数组使每个项目都可观察(我还没有看到如何做到这一点)或者我应该指定一个更改事件?或其他什么?

1 个答案:

答案 0 :(得分:2)

将“普通javascript对象”转换为具有可观察属性的视图模型有两种主要方式:

  1. 自动,通过ko.mapping.fromJS
  2. 手动。
  3. 如果您想使用选项2,我会给出答案。如果您想自动执行(1),最好查看文档和示例here

    在下面的代码中,我编写了一个将普通javascript对象和数组转换为ko.observableko.observableArray属性的示例。每个viewmodel都有一个构造函数或静态create方法,它“知道”如何处理指定的数据格式。对于数据中的每个属性,您可以选择:

    1. 忽略它(当它未在视图中呈现时,它在视图模型中不起作用)
    2. 将其设为常规属性(在视图中静态渲染时)
    3. 使其可观察(当需要在视图中更新时)
    4. 然后,您可以添加ko.computed属性和方法,以使您的视图具有交互性。

      var Day = function(initialHours) {
        this.hours = ko.observable(initialHours || 0);
      };
      
      Day.create = function(data) {
        return new Day(data.Hours);  
      }
      
      var Week = function(initialDays) {
        this.days = ko.observableArray(initialDays.map(Day.create));
        
        this.totalHours = ko.pureComputed(function() {
          return this.days().reduce(function(sum, day) {
            return sum + parseInt(day.hours(), 10);
          }, 0);
        }, this);
      };
          
      Week.create = function(dayArray) {
        return new Week(dayArray);
      };
      
      var Employee = function(employeeData) {
        this.name = employeeData.Name;
        this.workWeek = Week.create(employeeData.WorkWeek);
      };
      
      Employee.create = function(employeeData) {
        return new Employee(employeeData);
      };
      
      var testData = [{
        Name: "John Doe",
        WorkWeek: [
          { Hours: 4 },
          { Hours: 8 },
          { Hours: 8 },
          { Hours: 8 },
          { Hours: 6 }
        ]
      }];
        
      var vm = {
        employees: testData.map(Employee.create)
      };
      
      ko.applyBindings(vm);
      input[type="number"] { width: 30px }
      <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
      
      
      <ul data-bind="foreach: employees">
        <li>
          <div data-bind="text: name"></div>
          <div data-bind="with: workWeek">
            <!-- ko foreach: days -->
            <input data-bind="value: hours" type="number"/> -
            <!-- /ko -->
            <span data-bind="text: 'total: ' + totalHours()"></span>
          </div>
        </li>
      </ul>