Фильтровать параметры списка выбора на основе пользовательского ввода, сохраняя элементы, которые уже были выбраны - PullRequest
0 голосов
/ 10 февраля 2020

Html Код

<input type="text" class="radius" placeholder="SerialNo" data-bind="textInput: fromSerialNo" />
<br/>
<select data-bind="options: filteredInventoryList,
                   optionsText: function(item) {
                     return item.Id + ' (' + item.SerialNo + ')';
                   },
                   selectedOptions: selectedEquipment                   
                   " size="5" multiple="multiple" style="width: 300px;"></select>

Пример данных (упрощенно):

  var inventory = [{
      Id: "1",
      SerialNo: "00001"
    },
    {
      Id: "2",
      SerialNo: "00002"
    },
    {
      Id: "3",
      SerialNo: "10003"
    },
    {
      Id: "4",
      SerialNo: "10004"
    }
  ];

Код выбивания:

function viewModel() {
  var _root = this;
  // User input serialNo for filtering
  _root.fromSerialNo = ko.observable();
  // selectedOptions of the select list
  _root.selectedEquipment = ko.observableArray();
  // parent list of all equipment
  _root.fromInventoryList = ko.observableArray(inventory);

  // filtered list based on serialNo user input (should including the previously selected items)
  _root.filteredInventoryList = ko.computed(function() {
      var filteredList = ko.observableArray(null);

      if (!_root.fromSerialNo()) {
        // This works perfect, allows the user to select one or more item from the list.
        return _root.fromInventoryList();
      }
      else {
        // The following works and allow users to filter the parent list of equipment

        // Only show items that begin with the SerialNo entered
        filteredList(ko.utils.arrayFilter(_root.fromInventoryList(), function (item) {
                    return item.SerialNo.startsWith(_root.fromSerialNo());
                }));

        return filteredList();
      }
  });
}

Все отлично работает с точки зрения фильтрации список основан на серийном номере, который вводит пользователь. Пример здесь https://jsfiddle.net/JohnnyCodes/5h9pnqLg/.

Вариант использования:

  • Пользователь выбрал первый элемент в (Id: 1, серийный 00001)
  • Затем пользователь вводит 1 в фильтр SerialNumber
    • . Я бы хотел, чтобы список содержал выбранный элемент (Id: 1, Serial 00001), а также два элемента, серийные номера которых начинаются с 1

Проблема в том, что существует какая-то рекурсивная ссылка, и список начинает становиться сомнительным.

Введите 1, чтобы отфильтровать, затем изменить его на 0, затем изменить его на 1

Вот пример, https://jsfiddle.net/JohnnyCodes/cs4z9xpg/5/

Довольно часто это что-то действительно простое и глупое, я упустил из виду, но какое-то время ходил кругами сейчас же. Не возражал бы против другой пары глаз.

Спасибо

Ответы [ 2 ]

0 голосов
/ 11 февраля 2020

Предложение Джейсона Спейка было полезным, но оно только решило часть проблемы.

Вот решение, которое я использовал, надеюсь, это когда-нибудь кому-нибудь поможет:

_root.filteredInventoryList = ko.computed(function () {
            var filteredResults = ko.observableArray([]);

            // Filter fromInventoryList
            if (!_root.fromSerialNo()) {
                return  ko.utils.arrayPushAll(filteredResults(), _root.fromInventoryList());
            }
            else {
                // Add the selected items ot the array
                ko.utils.arrayPushAll(filteredResults(), _root.selectedEquipment());

                // Only show items that match
                filteredResults().push.apply(filteredResults(), ko.utils.arrayFilter(_root.fromInventoryList(), function (item) {
                    // Important, don't add the item if it was added with selectedEquipment
                    if (filteredResults().indexOf(item) < 0) {
                        return item.SerialNo().startsWith(_root.fromSerialNo());
                    }
                }));

                return filteredResults();
            }
        });
0 голосов
/ 11 февраля 2020

Проблема заключается в следующей строке

// Default the list to include the selected items.
filteredList(_root.selectedEquipment());

Наблюдаемые используют стандартный массив в качестве базовых данных, но когда вы инициализируете наблюдаемую с использованием существующего массива, наблюдаемая использует этот массив в качестве базового массива вместо создание нового массива, и все ссылки на него сохраняются. Это означает, что на следующем l oop сквозном, даже если ваш filteredList var имеет новую область видимости, он затем возвращается к тому же существующему массиву (selectedEquipment), и этот массив все еще содержит значения из последнего отзыва c.

Изменение строки так, чтобы элементы добавлялись к наблюдаемой, созданной в верхней части функции, без повторного использования массива selectedEquipment уровня root, должно решить проблему:

ko.utils.arrayPushAll(filteredList, _root.selectedEquipment());
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...