【问题标题】:knockout js prevents existing html observable from updating淘汰 js 阻止现有的 html observable 更新
【发布时间】:2015-11-26 22:40:41
【问题描述】:

我刚刚开始学习 knockout.js,并且在管理 observables 和正确更新它们方面有点卡住了。代码见jsfiddle。

 self.addItem = function(item, event){
    ptitle = $(event.currentTarget).prev('h3').text();

    self.items.push({
      productQty: self.productQty(),
      productClip: self.productClip(),
      productTitle: ptitle
    });
  }

http://jsfiddle.net/L61qhrc1/

我拥有的是现有 html 元素的列表。我想从该列表中创建另一个列表,其中包含一些可以设置的输入字段。它大部分都在工作,但我无法从我一直在查看的网络示例中弄清楚。

当一个字段更新列表中的所有字段时,我只想更新我当前正在更新的字段而不是整个列表。

任何好心人可以指出我正确的方向吗? 干杯。

【问题讨论】:

  • “我拥有的是现有 html 元素的列表” - 你应该拥有的是数据项列表。 HTML(视图)应该是数据的函数,而不是相反。

标签: javascript knockout.js


【解决方案1】:

正如我在评论中所说,您的用户界面必须是您的数据和视图模型的逻辑结果。您的视图模型绝不能关心视图的细节。

另外,your fiddle 在我看来设计过度。

以下是我从您的样本中收集到的内容,但方式不那么拜占庭式。

  • 制作独立的独立视图模型。理想情况下,制作它们以便它们可以从您传递给构造函数的数据中引导自己。
  • 使用模板可以保持视图的 HTML 整洁并提高模块化和可重用性。
  • 对于更复杂的数据,请考虑使用映射插件来引导您的模型。
  • 请咨询 Unique ids in knockout.js templates,了解创建工作 <input> / <label> 对的方法。

function ListItem(data, parent) {
    var self = this;
    data = data || {};

    self.productQty = ko.observable(data.productQty);
    self.productClip = ko.observable(!!data.productClip);
}

function Product(data) {
    var self = this;
    data = data || {};

    self.title = ko.observable(data.title);
    self.id = ko.observable(data.id);
    self.items = ko.observableArray();
    self.newItem = new ListItem();

    self.addItem = function () {
        self.items.push(new ListItem(ko.toJS(self.newItem), self));
    };
    self.removeItem = function (item) {
        self.items.remove(item);
    };
}

function ProductList(data) {
    var self = this;
    data = data || {};

    self.products = ko.observableArray(ko.utils.arrayMap(data.products, function (p) {
        return new Product(p);
    }));
}

var vm = new ProductList({
    products: [
        {title: "ProductName 1", id: "ProductId 1"},
        {title: "ProductName 2", id: "ProductId 2"}
    ]
});

ko.applyBindings(vm);
ul {
    list-style-type: none;
    padding: 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<div class="container">
    <div class="m-col-6">
        <ul data-bind="foreach: products">
            <li data-bind="template: 'productTemplate'"></li>
        </ul>
    </div>
</div>

<hr />
<pre data-bind="text: ko.toJSON($data, null, 2)"></pre>

<script type="text/html" id="productTemplate">
    <h1 data-bind="text: title"></h1>
    <p data-bind="text: id"></p>
    <div data-bind="with: newItem">
        <input type="checkbox" data-bind="checked: productClip" />
        <label>has pump clips</label>
        <input type="number" data-bind="value: productQty" />
        <button data-bind="click: $parent.addItem">add to list</button>
    </div>
    <ul data-bind="foreach: items">
        <li>
            <!-- ko template: 'itemsTemplate' --><!-- /ko -->
            <button data-bind="click: $parent.removeItem">Remove</button>
        </li>
    </ul>
</script>

<script type="text/html" id="itemsTemplate">
    <b data-bind="text: $parent.title"></b>
    <span data-bind="text: productClip() ? 'has' : 'does not have'"></span> pump clips
    (<span data-bind="text: productQty"></span>)
</script>

【讨论】:

  • 好的,但是在这里你已经彻底改变了功能。产品列表是预渲染的,它来自一个 cms。输出应该是单个元素,但这里每个产品都有一个输出元素。问题只是关于如何阻止预呈现列表中的所有输入字段在更改时更新。
  • 嗯,这就是我理解你的样本的方式。我的代码解决了你的问题的一个超集,你总是可以从它那里拿走功能。您的两个列表会同时更新,因为您实际上只有一个列表。您必须创建两个单独的视图模型,而不是将两个 HTML 部分绑定到同一个模型。
  • 谢谢我接受你的回答,因为原则是正确的。预渲染输入不需要使用淘汰赛 observable,正如您评论的“过度设计”。但在内部仅用于提交按钮以检索输入值并推送到篮子中大部分动态更新发生的可观察列表(将发生在本示例范围之外)。感谢您指出我正确的方向@Tomalak
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-06-02
  • 2014-08-27
  • 1970-01-01
  • 1970-01-01
  • 2013-04-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多