нокаутная фильтрация таблиц js нарушена в более новых версиях

#javascript #knockout.js

#javascript #knockout.js

Вопрос:

Я пытаюсь реализовать эту функциональность в этой демонстрации: http://opensoul.org/2011/06/23/live-search-with-knockoutjs /

Мне удалось заставить все работать, но в демонстрации используется очень старая версия knockout. Когда я обновляю нокаутную версию, функциональность прерывается.

Это мой обновленный код:

 $(function() {
  var assets = [
    {id: "1", poster: "Pic010.jpg", name: "Mike", category: "category1", type: "Movie", popup: "1" },
    {id: "2", poster: "Pic06.jpg", name: "James", category: "category2", type: "Movie", popup: "2" },
    {id: "3", poster: "Pic04.jpg", name: "John", category: "category1", type: "Pop-up", popup: "3" },
    {id: "4", poster: "Pic07.jpg", name: "Bob", category: "category2", type: "Pop-up", popup: "4" },
    {id: "5", poster: "Pic011.jpg", name: "Mary", category: "category3", type: "Promo", popup: "5" }
  ];

  var viewModel = {
    assets: ko.observableArray(assets),

    query: ko.observable(''),

    search: function(value) {
      viewModel.assets.removeAll();
      for(var x in assets) {
        if(assets[x].name.toLowerCase().indexOf(value.toLowerCase()) >= 0) {
          viewModel.assets.push(assets[x]);
        }
      }
    }
  };

  viewModel.query.subscribe(viewModel.search);

  ko.applyBindings(viewModel);
});
 

Отображение:

     <form action="#">
      <input class="form-control" placeholder="Search…" type="search" name="q" data-bind="value: query, valueUpdate: 'keyup'" autocomplete="off">
    </form>

  <div class="content">
    <table>
      <tbody data-bind="foreach:assets">
        <tr>
    <td style="vertical-align: middle" data-bind="text: id">amp;nbsp;</td>
    <td><img data-bind="attr:{ src: '/manager/files/'   poster }" height="100px" /></td>
    <td style="vertical-align: middle" data-bind="text: name"></td>
    <td style="vertical-align: middle" data-bind="text: category"></td>
    <td style="vertical-align: middle" data-bind="text: type"></td>
    <td style="vertical-align: middle" data-bind="text: popup"></td>
    <td class="actions" style="vertical-align: middle">
        <a href="/Assets/edit/5" data-bind="attr:{ href: '/Assets/edit/'   id }"><i class="fa fa-pencil-square-o"></i></a>
        <form data-bind="attr:{ action: '/Assets/delete/'   id, name: 'delete_'   id, id: 'delete_'  id }" style="display:none;" method="post"><input type="hidden" name="_method" value="POST"></form>
        <a href="#" ><i class="fa fa-trash-o"></i></a>
    </td>
</tr>
    </tbody>
        </table>
  </div>
 

вот примеры, работающие с версией Knockout 1.21: http://jsfiddle.net/7ZLdk/1 / пример, не работающий с версией 3.0: http://jsfiddle.net/7ZLdk/2 /

Ответ №1:

Это поведение было изменено еще в 2011 году: обновлены remove и removeAll для изменения их базовых массивов, а не для создания новых массивов

Итак, теперь, когда вы вызываете removeAll an ko.observableArray , он удаляет элементы из базовых массивов, поэтому в вашем случае он очищает ваш исходный assets массив.

Быстрым решением было бы клонировать массив при назначении вашему ko.observableArray :

 assets: ko.observableArray(assets.slice(0)),
 

Демонстрационный JSFiddle.

Лучшим и более современным решением было бы использовать ko.computed свойство и arrayFilter вспомогательный метод для выполнения фильтрации:

  assets: ko.computed(function () {
     if (!viewModel.query())
         return assets;
     return ko.utils.arrayFilter(assets, function(item) {
        return item.name.toLowerCase().indexOf(viewModel.query().toLowerCase()) >= 0;             
     });
 }, null, {deferEvaluation: true})
 

Демонстрационный JSFiddle.