【问题标题】:Knockout apply binding after observable array change可观察数组更改后敲除应用绑定
【发布时间】:2016-07-27 19:26:57
【问题描述】:

我有一个表,其中包含从淘汰的可观察数组中获得的项目,用户输入搜索文本并且巧合填充 observableArray,该表显示在模式上。每个项目都有一个按钮来打开另一个具有某些功能的模式(因为不相关而被省略)。如果 observableArray 长度大于 0,表格必须显示项目,否则必须显示一行以表示没有结果可显示。

<tr style="display: none" data-bind="visible: items().length == 0">
    <td class="text-center alert alert-warning" colspan="4"><b>There's no coincidences</b></td>
</tr>

我的视图模型:

var viewModel = function () {
    self.items= ko.observableArray([]);

    //Modal is already on html, but not visible, to show it I use this
    $('#searchProduct').modal('show');

    //When modal is closed, the table is cleaned, so the items in observableArray are removed
    $('#searchProduct').on('hidden.bs.modal', function () {
        self.items.removeAll();
    });
}

问题是第一次,可见绑定工作正常,但是当 observableArray 长度发生变化时(在隐藏时调用 removeAll 时),绑定不会再次应用。我知道是因为绑定已经应用,所以当 observableArray 发生变化时,长度会更新,但条件不能再次呈现 html。

如何通过淘汰赛解决这个问题?

(我尽量说得很具体,但如果需要更多信息,我可以更新信息更清楚)

【问题讨论】:

  • 而不是全部删除,请您尝试重置,例如 self.items({})。它重置了阵列。然后添加您的新项目
  • 谢谢你,我测试了这个解决方案,但仍未解决。我想要完成的是,当从 observableArray 中删除项目并且长度等于 0 时,会显示一条消息告诉没有巧合的行。
  • 你能不能为它创建一个小提琴..?
  • 我不知道如何创建一个,我对编程很陌生,我现在正在研究如何创建一个,谢谢你的帮助,请耐心等待。
  • 另外,请注意,在将它们与 KnockoutJS 结合时,您需要使用 custom bootstrap modal binding handlers。不要在 view model 中进行 DOM 操作(例如 on 处理程序),这就是绑定处理程序的用途。

标签: javascript knockout.js


【解决方案1】:

您发布的代码应该可以正常工作。这是一个例子:

function Item() {
  self.txt = ko.observable("Test observable");
}

function RootViewModel() {
  var self = this;
  self.items = ko.observableArray([new Item(), new Item()]);

  $('#searchProduct').modal('show');

  $('#searchProduct').on('hidden.bs.modal', function () {
    self.items.removeAll();
  });
}

ko.applyBindings(new RootViewModel());
pre { background: white; padding: 10px; color: #333; font: 11px consolas; border: 1px solid #ddd; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/js/bootstrap.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>

<div id="searchProduct" class="modal fade">
  <div class="modal-dialog">
    <div class="modal-content">Fake Modal</div>
  </div>
</div>

<table>
  <tbody>
    <tr style="display: none" data-bind="visible: items().length == 0">
      <td class="text-center alert alert-warning" colspan="4"><b>There's no coincidences</b>
      </td>
    </tr>
    <!-- ko foreach: items -->
    <tr>
      <td data-bind="text: txt"></td>
    </tr>
    <!-- /ko -->
  </tbody>
</table>

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

但请注意,我建议使用 a custom binding handler for show/hide of a bs modal,您不应在视图模型中处理 DOM 交互(如 on 处理程序)。

【讨论】:

  • 第一次加载模态时,observableArray 为空并且条件 items().length == 0 工作正常,但是当我搜索产品并填充 observableArray 时,我关闭模态并调用 removeAll,这清除了数组并且 items().length 等于零但是当我再次打开模式时,条件 items().length == 0 不起作用,因为没有显示这个 html 没有巧合
  • 可能是,但问题中的代码不足以重现
【解决方案2】:

调用 removeAll 会清空底层数组,并且您的两个 observable 似乎引用了同一个数组。而不是调用 removeAll 请按照self.items([]); 进行操作

我创建了一个小提琴示例,用于添加到数组并从数组中删除所有内容。

http://jsfiddle.net/d7mpc6wa/4/

我看不到您的完整 HTML 代码,所以我在这里创建了一个类似的示例。

HTML

<table>
    <tbody data-bind="foreach: items">
        <tr><td data-bind="text:$data.name"></td></tr>
    </tbody>
    <tbody>
        <tr data-bind="visible: items().length == 0">
            <td class="text-center alert alert-warning" colspan="4"><b>There's no coincidences</b></td>
        </tr>
    </tbody>
</table>

<button data-bind="click:cleanArray">Clean Array</button>
<button data-bind="click:addArray">Add Array</button>

视图模型

   function VM() {
     var self = this;
     var arr = [{name:'name 1'},{name:'name 2'},{name:'name 3'}];     
     self.items = ko.observableArray(arr);
     self.cleanArray = function(){
       self.items([]);
     }

     self.addArray = function(){
       self.items([]);
       self.items(arr);
       console.log(self.items());
     };
   }
  ko.applyBindings(new VM());  

如果有帮助请告诉我

更新

所以您在这里我们可以将数组中的项目删除为self.items([]);self.items.removeAll();,因此略有不同。

self.items([]); 将用新的空数组替换当前数组。但是self.items.removeAll() 将从 self.items 中删除所有项目 + 它将清空数组实例。

self.array = ['1', '2', '3'];
self.myArray1 = ko.observableArray(self.array);
self.myArray1.removeAll(); 

将清空self.myArray1 + 将清空self.array

下面的例子清楚地说明了区别,请看一下。

http://jsfiddle.net/LCQQH/

谢谢

【讨论】:

  • 不要认为这个建议是正确的。 The relevant docs 声明 removeAllobservableArrays 上的正确方法,应该正确更新视图。引入自定义数组清理函数不会有太大变化。
  • 我不知道发生了什么,为了测试,我打印 items().length 的值并且正在正确更新,我的意思是,当调用 removeAll 时,长度等于零,但是对于出于某种原因,这句话 不起作用。感谢机器人的帮助,我会试着找出这里有什么问题。
  • @Well whiser,我已经为 self.items([]) 更改了 removeAll,但仍然无法正常工作,感谢您的帮助和创建 jsfiddle,我非常感谢。
【解决方案3】:

我很惭愧,我发布的这段代码的一切都很好,错误是当我关闭模式时,我正在删除 html 中的所有警报类,这显然是删除了 td 元素中的警报警告,所以取而代之或删除所有警报,这不是目的,我正在从模态中删除警报危险。我真的很抱歉在 SO 上发布了这个愚蠢的问题,@Jeroen,我知道将 jQuery 与淘汰赛混合以隐藏模式存在问题,只是我不知道如何以正确的方式做到这一点。非常感谢您的回答。

【讨论】:

    猜你喜欢
    相关资源
    最近更新 更多
    热门标签