Svelte virtual list component – function not working after filtering list

Asked By: Anonymous

I am using the virtuallist component in a svelte project. I have added filtering to the list. My issue is that a function in my project stops working when I filter the list, I’m assuming because the list item is not yet in the dom when filtered?

The project converts medical units from metric units to international units using two inputs. Changing one input automatically converts the other.
Before filtering, everything works well with conversion but after entering a item name, (e.g. Type Zinc), the input conversion fails in the filtered items. No conversion occurs.
I’ve looked into afterUpdate as an option but not sure how to implement it.

———Added Info ——————-

The issue is with list items not yet in view. Try typing “zinc” and then changing the input values of Zinc (fails) vs typing Acetone (item already in view) and changing those inputs (it works).

Here is a working REPL

The script:

 <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>

With simplified html code:

 <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>

Thanks for any help in getting this to work!


Solution

Answered By: Anonymous

It’s a small issue with your filter. You convert the product name to lower case but not the filter term 😉 If you enter acetone instead of Acetone, then it works. The fix:

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

Edit:

The issue with not calling the function for some filtered element is that you display the filteredList but still do the lookup on the unitsH list. Change it to this and it works:

    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);
    }

Happy hacking!


Windows 10 Kaufen Windows 10 Pro Office 2019 Kaufen Office 365 Lizenz Windows 10 Home Lizenz Office 2019 Home Business Kaufen windows office 365 satın al follower kaufen instagram follower kaufen porno