Knockout:observableArray的可观察输入数组

时间:2017-07-24 03:44:54

标签: javascript knockout.js foreach

  

我在项目飞行管理计算机中遇到route.htmlforeach绑定问题。

问题1:value中的observableArray绑定全部同时更新

对于javascript中的路线,我设置了ko.observableArray Array ko.observable(听起来很混乱,但下面附带了代码):

/* All bindings applied to viewmodel already */

var route = ko.observableArray();
var DEFAULT_ROUTE = [
    ko.observable(), // Waypoint Name
    ko.observable(), // Lat.
    ko.observable(), // Lon.
    ko.observable(), // Altitude Restriction
    ko.observable(false), // Waypoint isValid
    ko.observable('') // Waypoint information
];

单击特定按钮会使DEFAULT_ROUTE毫无问题地添加,因为它会调用

route.push(DEFAULT_ROUTE);

HTML代码看起来大致如此,没有UI问题:

<tbody data-bind="foreach: route">
    <tr class="wpt-row">
        <td><input data-bind="value: $data[0]"></td> <!--waypoint input-->
        <td><input data-bind="value: $data[1]"></td> <!--lat. input-->
        <td><input data-bind="value: $data[2]"></td> <!--lon. input-->
        <td><input data-bind="value: $data[3]"></td> <!--alt. input-->
    </tr>
</tbody>

然而,如果外部ko.observableArray中有多个数组,则会出现问题,因为在UI和javascript中更改一个输入值都会更新所有每个数组中的值。例如:

var route = ko.observableArray([DEFAULT_ROUTE, DEFAULT_ROUTE, DEFAULT_ROUTE]);

// Then, outside viewmodel (in javascript console)
route()[0][0]('WPT'); // Sets the waypoint of the first input field to be 'WPT'

// Later
route()[0][0](); // 'WPT', correct
route()[1][0](); // 'WPT', incorrect, should be undefined
route()[2][0](); // 'WPT', incorrect, should be undefined

我在不同的文件中设置了类似的foreach,但<input>仅为<span>,而data-bindtext: $data[x]而不是{{1} }}。这个不同的文件工作正常没有问题。不同的文件是log.html

问题2(或更确切地说,问题)

修复value问题后,我希望在同一数组中的另一个值发生更改时更新单个数组(一个路点输入字段)中的某些特定值。即。

route

我阅读了文档并且有一个// Scenario 1, waypoint is a valid waypoint with proper coords var waypoint = 'WAATR'; var coords = getWaypoint(waypoint); // [42.1234, -70.9876] route()[0][0](waypoint); // route()[0][0]() is now 'WAATR' // route()[0][1] and route()[0][2] should automatically update with value `coords[0]` and `coords[1]` // route()[0][4] should be set to true (valid waypoint) // Scenario 2, waypoint is NOT a valid waypoint var waypoint = 'IDK'; var coords = getWaypoint(waypoint); // [] route()[0][0](waypoint); // route()[0][0]() is now 'IDK' // route()[0][1] and route()[0][2] should remain undefined, waiting for users to manually input coordinates // route()[0][4] should be false (invalid waypoint) 函数,但我真的不明白它。现在的挑战是如何将这些自动填充函数限制为特定数组(航路点输入字段)而不是(如问题#1)限制输入的整个数据表。

如果有人能提供帮助,我将不胜感激,因为extend是整个项目最重要的特征。

3 个答案:

答案 0 :(得分:0)

问题1: 这是一个javascript相关的问题,而不是knockoutjs。您一次又一次地推送对同一对象的引用,从而使您的observableArray包含对同一对象的多个引用。您应该更改代码,改为使用工厂函数:

var DEFAULT_ROUTE = function(){
  return [
    ko.observable(), // Waypoint Name
    ko.observable(), // Lat.
    ko.observable(), // Lon.
    ko.observable(), // Altitude Restriction
    ko.observable(false), // Waypoint isValid
    ko.observable('') // Waypoint information
  ];
};

然后推动:

route.push(DEFAULT_ROUTE());

这样每次都会添加一个新对象。

答案 1 :(得分:0)

你应该使用对象而不是数组。它使一切都更容易阅读和理解,并将极大地帮助调试。

var Route = function() {
  this.waypointName = ko.observable();

  this.lat = ko.observable();
  this.lon = ko.observable();

  this.altitudeRestriction = ko.observable();
  this.isValid = ko.observable(false);
  this.waypointInfo = ko.observable('');
};

就像您已经想到的那样,现在可以通过调用new Route()来使用它。您将解决问题1并拥有更易于阅读和保护的代码。解决问题2的正确基础:

因为您现在拥有明确定义的模型,所以您可以使用subscribecomputed开始定义属性之间的关系。您想要更改waypointName属性并让其他属性自动更新:

var Route = function() {
  this.waypointName = ko.observable();

  // Automatically updates when you set a new waypoint name
  var coords = ko.pureComputed(function() {
    return getWaypoint(this.waypointName());
  }, this);

  // Check if we got correct coords
  this.isValid = ko.pureComputed(function() {
    return coords().length === 2;
  }, this);

  // Auto-extract lat from coords, null if invalid
  this.lat = ko.pureComputed(function() {
    return this.isValid() 
      ? coords()[0]
      : null;
  }, this);

  // Auto-extract lat from coords, null if invalid
  this.lon = ko.pureComputed(function() {
    return this.isValid() 
      ? coords()[1]
      : null;
  }, this);
};

您现在有一个默认Route isValid: falselat: nulllon:null,当您将waypointName设置为字符串值时,例如{{1 },所有属性都会自动更新。

答案 2 :(得分:0)

user3297291,谢谢你的帮助!根据你的建议,我能够完成这个功能:

var Route = function () {

    var self = this;

    // Waypoint name
    var _fix = ko.observable();
    self.fix = ko.pureComputed({
        read: function () {
            return _fix();
        },
        write: function (val) {
            _fix(val);

            var coords = get.waypoint(val);
            var isValid = coords[0] && coords[1];

            self.lat(coords[0], isValid);
            self.lon(coords[1], isValid);
            self.info(coords[2]);
        }
    });

    // Latitude
    var _lat = ko.observable();
    self.lat = ko.pureComputed({
        read: function () {
            return _lat();
        },
        write: function (val, isValid) {
            _lat(val);
            self.valid(isValid ? true : false);
        }
    });

    // longitude
    var _lon = ko.observable();
    self.lon = ko.pureComputed({
        read: function () {
            return _lon();
        },
        write: function (val, isValid) {
            _lon(val);
            self.valid(isValid ? true : false);
        }
    });

    // Is waypoint valid
    self.valid = ko.observable(false);

    // Waypoint info
    self.info = ko.observable();

};