How to make a search filter in svelte
Asked Answered
M

1

5

I have two components that are very far away in the component tree and I have doubts about how to communicate between both. I have the search component, listItems and a store.

store.svelte

<script context="module" lang="ts">
 import type {Items} from '../../Models/Items.model';
 import { writable } from 'svelte/store';

 export const dataItems = writable<Items[]>([]);

  const filterInfo = (term:string) => {
     dataItems.update(item => {
           item.filter(x => {
                return x.name.toLowerCase().includes(term.toLowerCase())
                || x.description.toLowerCase().includes(term.toLowerCase());
           })
           return dataItems;
        })
    }*/


export const dispatcher = {filterInfo};

</script>

search component

<script lang="ts">
    import { dispatcher } from './ViewI/store.svelte';
    

    let value:any;

    const handleChange = () => {
     dispatcher.filterInfo(value)
    console.log(value)
     }
    
    
</script>

<Search>
 <input bind:value
 on:input={handleChange}>
</Search>

listItems component

import type {Items} from '../../Models/Items.model';
import {dataItems,dispatcher} from './store.svelte';

export let items:Items[] =[];
export let value:any;

$:filterItems = items;

$: {
  filterItems = $dataItems.filter((item:any) => {
    return item.name  || item.description
  });
  
  dispatcher.filterInfo(value);
 }



</script>

<main>
  
      {#each [...filterItems] as item }
           <CardItems
              name={item.name}
              description={user.description}
              id={item.id}
            /> 
           {/each}

</main>

The question is how to communicate both components with the value that you write in the input and make the filter.

Music answered 6/1, 2021 at 22:38 Comment(1)
You can subscribe to a store and also set or update a writeable store and even bind a store to an input. See the docs.Arabinose
M
13

You can accomplish this using a derived store. Here is a small example.

Set up three stores: term will hold the term being searched for, items will hold the full list of items, and filtered will be a derived store that contains the items that include the term. It will automatically be updated whenever term or items change.

// stores.js
import { writable, derived } from 'svelte/store';

export const term = writable('');
export const items = writable(['dog', 'cat', 'fish', 'iguana']);
export const filtered = derived(
    [term, items], 
    ([$term, $items]) => $items.filter(x => x.includes($term))
);

You can then use these stores across your application. Your Search component can set the term being searched for like so.

<!-- Search.svelte -->
<script>
    import {term} from './stores.js';
    let val = '';
    
    $: term.set(val);
</script>

<label for="searchInput">Search</label>
<input bind:value={val} type="text" id="searchInput">

When you call term.set(val), the derived store will automatically be updated. You can use this store in any component in your application.

<!-- ListItems.svelte -->
<script>
    import { filtered } from './stores.js';
</script>

<ul>
{#each $filtered as item}
    <li>{item}</li>
{/each}
</ul>

You can see a working example in the Svelte REPL.

Meld answered 7/1, 2021 at 16:26 Comment(1)
This is exactly what I'm trying to achieve in an product listing page, and it works fine when you are searching or filtering by one condition, but I'm guessing how to extend it to apply several conditions like amazon sidebar.Anglocatholic

© 2022 - 2024 — McMap. All rights reserved.