Компонент виртуального списка Svelte - функция не работает после фильтрации списка

Я использую виртуальный компонент в компактном проекте. Я добавил фильтрацию в список. Моя проблема в том, что функция в моем проекте перестает работать, когда я фильтрую список, я предполагаю, потому что элемент списка еще не находится в домене после фильтрации?

Проект преобразует медицинские единицы из метрических единиц в международные единицы с использованием двух входов. Изменение одного входа автоматически преобразует другой. Перед фильтрацией все работает с преобразованием, но после ввода имени элемента (например, Type Zinc) преобразование входных данных не выполняется в отфильтрованных элементах. Преобразования не происходит. Я рассматривал afterUpdate как вариант, но не знаю, как его реализовать.

--------- Добавлена ​​информация -------------------

Проблема заключается в том, что элементы списка еще не просматриваются. Попробуйте ввести «цинк», а затем изменить входные значения цинка (сбой), а не ввести «Ацетон» (элемент уже виден) и изменить эти входные значения (он работает).

Вот рабочий REPL

Сценарий:

 <script>
 import VirtualList from './VirtualList.svelte';
 import unitsH from './data.js';


let searchTerm = "";
let start;
 let end;
  $: filteredList = unitsH.filter(item => item.name.toLowerCase().indexOf(searchTerm) !== -1);

function setBothFromSIH(value, i) {
const {factor, siValue} = unitsH[i];
unitsH[i].siValue = +value;
unitsH[i].usValue = +(value / factor).toFixed(2);
}
function setBothFromUSH(value, i) {
const {factor, usValue} = unitsH[i];
unitsH[i].usValue = +value;
unitsH[i].siValue = +(value * factor).toFixed(2);
 }
  </script>

С упрощенным кодом HTML:

 <VirtualList items={filteredList} bind:start bind:end let:item >

<div class="border" style="overflow-x: scroll;"> <div><div>

          <div class="name">{item.name}</div>
         <span>Specimen: {item.specimen} </span>
     <span> Conversion Factor: {item.factor} </span>
        </div>
 <div>
  <label>US Range:{item.conventionalRange} {item.conventionalUnit}</label>
           <input  name="us{filteredList.indexOf(item)}" value={item.usValue} on:input="{e => setBothFromUSH(e.target.value, filteredList.indexOf(item))}"  type=number placeholder=" US">

         </div> 
 <div>
 <label>SI Range: {item.siRange} {item.siUnit}</label>
           <input name="si{filteredList.indexOf(item)}" value={item.siValue} on:input="{e => setBothFromSIH(e.target.value, filteredList.indexOf(item))}" type=number placeholder="SI">

         </div></div> </div>
 </VirtualList>

 <p>showing items {start}-{end}</p>

Спасибо за любую помощь в работе!


person Macsupport    schedule 08.06.2020    source источник


Ответы (2)


Это небольшая проблема с вашим фильтром. Вы переводите название продукта в нижний регистр, но не в термин фильтра;) Если вы вводите acetone вместо Acetone, то это работает. Исправление:

$: filteredList = unitsH.filter(item => item.name.toLowerCase().indexOf(searchTerm.toLowerCase()) !== -1);

Редактировать:

Проблема с невызовом функции для некоторого отфильтрованного элемента заключается в том, что вы отображаете filteredList, но по-прежнему выполняете поиск в списке unitsH. Измените его на это, и он работает:

    function setBothFromSIH(value, i) {
        const {factor, siValue} = filteredList[i];
        filteredList[i].siValue = +value;
        filteredList[i].usValue = +(value / factor).toFixed(2);
    }

    function setBothFromUSH(value, i) {
        const {factor, usValue} = filteredList[i];
        filteredList[i].usValue = +value;
        filteredList[i].siValue = +(value * factor).toFixed(2);
    }

Удачного взлома!

person Andreas Dolk    schedule 08.06.2020
comment
Спасибо, но проблема возникает, если вы ищете элемент, которого еще нет в поле зрения. Попробуйте ввести Zinc, и вы увидите проблему: никакого преобразования при изменении входного значения, как это происходит с Acetone. Фильтрация работает, но не преобразование входных данных. - person Macsupport; 08.06.2020
comment
У меня работает сейчас. Раньше Zinc не работало (но zinc показало два результата). После исправления также работает фильтрация по Zinc. По крайней мере, на REPL: svelte.dev/repl/f8e188dae0ee44cd940db42a5.23 / а> - person Andreas Dolk; 08.06.2020
comment
Хммм, не вижу, чтобы входы работали даже после очистки кеша. Фильтр всегда работал (лучше с вашим предложением!), Но изменение входного значения US на Zinc должно изменить значение на входе SI (или наоборот) в зависимости от коэффициента преобразования. Смотрите мою добавленную информацию - person Macsupport; 08.06.2020
comment
Понятно. Ваше описание ошибки теперь становится более ясным. Это была не функция фильтрации, а преобразование. - person Andreas Dolk; 08.06.2020
comment
@Macsupport Нашел свою ошибку :) - person Andreas Dolk; 08.06.2020

Ваша проблема вызвана использованием неправильного индекса, в обработчике изменений вы передаете индекс элемента в filteredIndex, но затем вы используете его для изменения элемента в этом индексе в массиве unitsH.

Вы можете убедиться в этом: - начать заново - отметить значение для ацетаминофена (индекс 0) - найти цинк - изменить значение цинка (индекс 0 в отфильтрованном списке) - очистить поиск

- >> Ацетаминофен изменился, потому что это индекс 0 в единицах H

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

<input name="si{filteredList.indexOf(item)}" value={item.siValue} on:input="{e => setBothFromSIH(e.target.value, unitsH.indexOf(item))}" type=number placeholder="SI">

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

person Stephane Vanraes    schedule 08.06.2020