Просмотр списка Knockout-Kendo не инициализируется после valueHasMutated

Я работаю над проектом, который требует от меня использования пользовательского интерфейса Kendo вместе с Knockout.js для мобильного приложения, в качестве способа привязки этих библиотек я использую библиотеку Knockout-Kendo, приложение состоит из простого списка продуктов с подробные представления для каждого продукта и корзины, однако у меня возникают проблемы с обновлением количества товаров в моей корзине.

Я использую привязки нокаут-кендо в своем приложении следующим образом:

<div data-role="view" id="cart" data-title="Cart" data-layout="main-layout">
    <div data-bind="if: items().length == 0">No items currently in cart</div>
    <ul data-role="listview" data-style="inset" data-bind="kendoListView: { data: items, template: cartTemplate }"></ul>
</div>

где шаблон:

<script type="text/x-kendo-template" id="cartListTemplate">
    <div class="km-listview-link cart-item-container" data-id="#= Id #">
      <div class="product-image">
      <img src="#= ImageUrl #">
    </div>
    <div class="product-description">
      <p>#= Name #</p>
      <p>#= formattedPrice #</p>
      <p>#= quantity #</p>
    </div>
    <a data-role="button" data-icon="delete" class="km-primary" data-bind="click: removeItem">Delete</a>
  </div>
</script>

и ViewModel:

CartViewModel : function () {
        var self = this;
        globalKo.cartItems = self.items = ko.observableArray(JSON.parse(localStorage.getItem('cart')) || []);
        self.cartTemplate = kendo.template($('#cartListTemplate').html());
        self.removeItem = function (vm, event) {
            var element = $(event.target).parents('div.cart-item-container');
            productId = element.data('id');
            var cartItem = globalKo.cartItems().filter(function (element) {
                return element.Id == productId;
            })[0];
            if (cartItem.quantity > 1) {
                cartItem.quantity --;
            } else {
                self.items.remove(cartItem);
            }
            app.saveCart(); 
            self.items.valueHasMutated(); 
        }
    }

Все это работает как задумано, за исключением того, что когда значение массива мутирует (вызывается функция valueHasMutated или в массив добавляется или удаляется элемент) кнопки внезапно перестают быть кнопками и превращаются в простой текст, они также не работают, поскольку они прекратите вызывать функцию, к которой они привязаны. Как видно из фрагментов кода, привязка кликов выполняется с помощью разметки и не работает должным образом.

Возможно, стоит отметить, что я вызываю функцию valueHasMutated, потому что в противном случае представление не обновляет количество товаров в корзине.

Чтобы проиллюстрировать проблему, вот несколько изображений:

Перед нажатием кнопки

«Перед

После нажатия кнопки

После нажатия кнопки

Я не совсем понимаю, почему это происходит, я предполагаю, что это как-то связано с пользовательским интерфейсом Kendo, а не с Knockout.js.

Я также сделал скрипт, демонстрирующий проблему, вы можете найти его здесь


person Max Rasguido    schedule 13.04.2016    source источник


Ответы (2)


Как указано в этой статье, полная поддержка интеграции кендо и нокаута отсутствует (http://www.telerik.com/blogs/knockout-js-and-kendo-ui---a-potent-duo), поэтому в некоторых сценариях некоторые обходные пути сделать.

Сначала попробуйте использовать шаблон Knockout:

<script type="text/html" id="cartListTemplate">
  <div class="km-listview-link cart-item-container" data-id="text: Id">
    <div class="product-image">
      <img data-bind="attr:{src: ImageUrl}">
    </div>
    <div class="product-description">
      <p data-bind="text: Name"></p>
      <p data-bind="text: formattedPrice"></p>
      <p data-bind="text: quantity"></p>
    </div>
    <button data-icon="delete" class="km-big" data-bind="kendoMobileButton: $root.removeItem">Delete</button>
  </div>
</script>

Обратите внимание, что тег «a» был изменен на простой тег кнопки, связывающий его с кнопкой мобильного кендо (https://rniemeyer.github.io/knockout-kendo/web/Button.html). Затем представление должно быть уведомлено об использовании шаблона Knockout вместо шаблона Kendo:

<div data-role="view" id="cart" data-title="Cart" data-layout="main-layout">
  <div data-bind="if: items().length == 0">No items currently in cart</div>
  <ul data-role="listview" data-style="inset" data-bind="kendoListView: { data: items, template: 'cartListTemplate', useKOTemplates: true }"></ul>
</div>

Наконец, чтобы заставить функцию удаления работать правильно, привяжите ее к модели представления и получите текущий элемент в качестве параметра:

self.removeItem = function(item) {
    if (item.quantity > 1) {
      var cartItem = self.items().filter(function(element) {
        return element.Id == item.Id;
      })[0];
      cartItem.quantity--;
      self.items.valueHasMutated();
    } else {
      self.items.remove(item);
    }
    app.saveCart();
  }.bind(self);

Единственное, что нужно знать, это то, что значение мутировало, обновляя вид, что иногда мешает виджетам кендо, поэтому библиотека нокаута кендо использует обычные теги, определяющие роль в атрибуте привязки данных. Это связано с тем, что в настоящее время нокаутирующая библиотека кендо не поддерживает инициализацию роли данных и вместо этого использует инициализацию привязки данных.

Рабочий пример можно найти по адресу: https://jsfiddle.net/aveze/Lykducos/.

person user2844914    schedule 19.04.2016

вы можете попробовать использовать шаблоны нокаута и knockout-kendo

  • На ваш взгляд

    <div data-role="view" id="cart" data-title="Cart" data-layout="main-layout">
        <div data-bind="if: !items().length === 0">No items currently in cart</div>
        <div data-bind="if: items().length"><p data-bind="text: items().length"></p><p> items currently in the cart</p></div>
        <ul data-role="listview" data-style="inset" data-bind="kendoListView: { data: items, template: 'cartListTemplate', useKOTemplates: true }"></ul>
    </div>
    

  • create the named template

    <script type="text/html" id="cartListTemplate">
    <li class="km-listview-link cart-item-container" data-bind="attr: {'id': Id}">
        <div class="product-image">
            <img data-bind="attr: {'src': ImageUrl}">>
        </div>
        <div class="product-description">
            <p data-bind="text: Name"></p>
            <p data-bind="text: formattedPrice"></p>
            <p data-bind="text: quantity"></p>            
        </div>
        <a data-role="button" data-icon="delete" class="km-primary" data-bind="click: $root.removeItem">Delete</a>
    </li>
    

  • remove items by splicing the array

    this.removeItem = function (item) {
        const deleteIndex = this.items.findIndex(i => i.Id === item.Id)
        if (deleteIndex > -1) {
            this.items.splice(deleteIndex, 1)
        }
    }.bind(this)
    
person Community    schedule 16.04.2016