Knockoutjs:如何使添加到列表中的输入值也可观察

Posted

技术标签:

【中文标题】Knockoutjs:如何使添加到列表中的输入值也可观察【英文标题】:Knockoutjs: how can I make the input value added to a list also observable 【发布时间】:2019-08-02 22:22:58 【问题描述】:

不确定我的措辞是否正确。

我有一个 observableArray,我可以从输入添加到该数组,还可以删除列表项。但是如果我修改创建的项目,我将失去与数组的连接。如何保持与数组的绑定?

Fiddle Attached

html

<div class="group-settings-container mt-4">
<div class="row">
<div class="col-md-3">
  <h4><i class="fas fa-object-group"></i> Create Groups</h4>
</div>

<div class="col-md-6">
  <div class="input-group">
    <input type="text" class="form-control create-group-name" data-bind="value: groupItemToAdd, valueUpdate: 'afterkeydown' " placeholder="Enter group name" value="">
    <div class="input-group-append">
      <button class="btn btn-primary add-group-btn" data-bind="click: addGroupItem, enable: groupItemToAdd().length > 0" type="button"><i class="fas fa-plus"></i>
                      Add group</button>
    </div>
  </div>
</div>


<div class="create-groups-container mb-4">
  <ul class="list-group create-group-list my-2" data-bind="foreach: allGroupItems">
    <li class="list-group-item">
      <div class="input-group">
        <input type="text" class="form-control created-group-input" data-bind="value: $data">
        <div>
          <button class="btn btn-danger remove-group-item-btn" data-bind="click: $parent.removeSelectedGroupItem" type="button"><i class="fas fa-times"></i>
                        Remove</button>
        </div>
      </div>
    </li>
  </ul>
</div>
<!-- end create groups container  -->

</div>
<!-- end group settings container -->

JS

 function ViewModel() 
 var self = this;
 self.groupItemToAdd = ko.observable("");
 self.allGroupItems = ko.observableArray([]);


 self.addGroupItem = function() 
 if ((self.groupItemToAdd() != "") &&     (self.allGroupItems.indexOf(self.groupItemToAdd()) < 0)) 
  self.allGroupItems.push(self.groupItemToAdd());
  
  self.groupItemToAdd(""); // clear the input
 

 self.removeSelectedGroupItem = function(index) 
 // self.allGroupItems.splice(index, 1);
// console.log(self.allGroupItems.splice(index, 1));
self.allGroupItems.remove(index);


// end ViewModel

ko.applyBindings(new ViewModel());

【问题讨论】:

如果答案解决了您的问题,请将其标记为accepted。见:What should I do when someone answers my question? 【参考方案1】:

您有一个observableArray。这意味着,对阵列的任何更改都会被跟踪和更新。它里面的项目只是字符串。他们不是observables。您从 UI 所做的任何更改都不会更新回视图模型。此行为不限于字符串。如果你有一个 observableArray 的常规 javascript 对象文字,同样的事情也适用。

来自documentation:

仅仅将一个对象放入observableArray 并不会使该对象的所有属性都成为observable。当然,如果您愿意,您可以使这些属性可观察,但这是一个独立的选择。 observableArray 只跟踪它持有的对象,并在添加或删除对象时通知侦听器。

因此,您可以将具有observable 属性的对象推送到observableArray,而不是向observableArray 添加字符串。现在跟踪item 属性的更改。将属性设为observable 很重要,否则您会遇到同样的问题。

function ViewModel() 
  var self = this;
  self.groupItemToAdd = ko.observable("");
  self.allGroupItems = ko.observableArray([]);

  self.addGroupItem = function() 
    if (self.groupItemToAdd() && !self.allGroupItems().some(a => a.item() === self.groupItemToAdd())) 
      self.allGroupItems.push(
        item: ko.observable(self.groupItemToAdd())
      );
    
    self.groupItemToAdd(""); // clear the input
  

  self.removeSelectedGroupItem = function(index) 
    self.allGroupItems.remove(index);
  


ko.applyBindings(new ViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.bundle.min.js"></script>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet" />

<div class="group-settings-container mt-4">
  <div class="row">
    <div class="col-md-3">
      <h4><i class="fas fa-object-group"></i> Create Groups</h4>
    </div>

    <div class="col-md-6">
      <div class="input-group">
        <input type="text" class="form-control" data-bind="value: groupItemToAdd, valueUpdate: 'afterkeydown' " placeholder="Enter group name">
        <div class="input-group-append">
          <button class="btn btn-primary add-group-btn" data-bind="click: addGroupItem, enable: groupItemToAdd().length > 0" type="button">Add group</button>
        </div>
      </div>
    </div>

      <ul class="list-group create-group-list my-2" data-bind="foreach: allGroupItems">
        <li class="list-group-item">
          <div class="input-group">
            <input type="text" class="form-control created-group-input" data-bind="value: item">
            <div>
              <button class="btn btn-danger remove-group-item-btn" data-bind="click: $parent.removeSelectedGroupItem" type="button">Remove</button>
            </div>
          </div>
        </li>
      </ul>
  </div>

  <span data-bind="text: allGroupItems().map(a => a.item())"></span>

注意:

您需要将foreach 中的输入绑定从$data 更改为item(可观察的属性名称)

要检查是否已添加组项目,请使用some,如下所示:self.allGroupItems().some(a =&gt; a.item() === self.groupItemToAdd())

最后一个 span 表明 observable 已更新

【讨论】:

以上是关于Knockoutjs:如何使添加到列表中的输入值也可观察的主要内容,如果未能解决你的问题,请参考以下文章

如何使列表框的一个选项将数据添加到新字段

knockoutjs 验证,立即验证

KnockoutJS:将 Observable 属性和函数添加到映射生成的 ObservableArray 中的对象

具有动态创建的局部视图的 KnockoutJS

KnockoutJS数组比较算法解析

KnockoutJS 中的 ViewModel 无法访问全局变量