vincjo / datatables

A toolkit for creating datatable components with Svelte
https://vincjo.fr/datatables
MIT License
363 stars 15 forks source link

Is there a way to clear the filters while at the same time reseting the input or select filter? #43

Closed ghost closed 12 months ago

ghost commented 1 year ago

Hello, I'm using clearFilters and while it works cleaning all the filters applied, it doesn't really reset the select for that filter. For example, after I run clearFilters function, my select still shows the selected filter (but the data change to no filter tho). I do have a wayaround this problem for now, like this:

    function clearFilters() {
        handler.clearFilters();

        document.getElementById('starred').selectedIndex = '0';
        document.getElementById('featured').selectedIndex = '0';
        document.getElementById('published_at').selectedIndex = '0';
    }

But it's extremely inefficient and it's not reusable as well since every page will have different filter. Is there any way to clear the filter while at the same time reseting any input or select that is used for that filter? Thank you.

vincjo commented 12 months ago

Hello, Have'nt found any solution yet. Need to take a closer look, maybe with two-way binding

vincjo commented 12 months ago

In the meantime, it is possible to pass an additional parameter to the filter component: a reactive value that increments each time handler.clearFilters() is called

<script lang="ts">
    import MyThFilter from './MyThFilter.svelte'
    export let handler: DataHandler

    let triggerClearFilters = 0

    const clearFilters = () => {
        handler.clearFilters()
        triggerClearFilters = triggerClearFilters + 1
    }
</script>

<button on:click={clearFilters}>Clear Filters</button>
<section>
    <MyThFilter {handler} {triggerClearFilters} filterBy="first_name"/>
    <MyThFilter {handler} {triggerClearFilters} filterBy="last_name" />
    <MyThFilter {handler} {triggerClearFilters} filterBy="email"/>
</section>

Then we can reset values in filter components:

<script lang="ts">
    export let triggerClearFilters: number 

    let value: string = null
    $: triggerClearFilters, value = null
</script>

Below is an example to see the result: https://vincjo.fr/datatables/test/clear-filters

vincjo commented 12 months ago

[UPDATE] You can use a simple on() method. Just released in 1.11.0

handler.on('clearFilters', () => value = '')

handler.on(event, callback) method executes callbacks once the event is triggered. It's all internalized, much easier to use.

Thanks for raising this issue.

ghost commented 12 months ago

@vincjo Thanks for your solution, but while it works if the filter function is in the same file as the filter input, I don't know how to use it when they're separated. I created a filter function in a component so it's reusable, and then I just call it on any page I like. Here are the example codes for this case.

FilterComponent :

<script>
    import { check } from '@vincjo/datatables';

    export let handler;
    export let id;
    export let defaultSelectedText;
    export let options;
    export let filterBy = null;

    let value = '';

    function filter() {
        if (!value) {
            return handler.filter(null, filterBy);
        }

        if (value === 'isNull' || value === 'isNotNull') {
            return handler.filter('Dummy String', filterBy, check[value]);
        }

        return handler.filter(value, filterBy);
    }
</script>

<select class="form-select" {id} bind:value on:change={filter}>
    <option value="" disabled="{value === ''}" hidden="{value === ''}">{defaultSelectedText}</option>
    {#each options as option}
        <option value="{option.value}">{option.text}</option>
    {/each}
</select>

ProductPage :

<script>
    import { DataHandler } from '@vincjo/datatables';
    import TableFilterSelect from '../../Components/TableFilterSelect.svelte';

    export let productsAndSolutions;

    const handler = new DataHandler(productsAndSolutions, { rowsPerPage: 10 });
    const rows = handler.getRows();
    const selected = handler.getSelected();
    const isAllSelected = handler.isAllSelected();
    const filterCount = handler.getFilterCount();

    $: productsAndSolutions, handler.setRows(productsAndSolutions);

    function clearFilters() {
        handler.clearFilters();

        document.getElementById('starred').selectedIndex = '0';
    }
</script>

<div class="mb-3">
    <label for="starred" class="fw-bold mb-2 text-1000">Starred</label>
    <TableFilterSelect {handler} id="starred" filterBy="starred" defaultSelectedText="Select Starred" options={[{"value": "1", "text": "Yes"}, {"value": "0", "text": "No"}]} />
</div>

<div class="modal-footer d-flex justify-content-end align-items-center px-4 pb-4 border-0 pt-3">
    <button type="button" class="btn btn-sm btn-phoenix-primary px-4 fs--2 my-0" on:click={clearFilters}>
        <span class="fas fa-arrows-rotate me-2 fs--2"></span>Reset
    </button>
</div>

If I need to call the FilterComponent, it's easy to pass the value, but since the Reset button itself isn't really calling a component, but rather just calling the handler.clearFilters() function, I have no way to pass the value. How do I pass the value if the filter function is in another file? Thank you.

vincjo commented 12 months ago

Hello @wojakmcwagies, ty for the answer

There is nothing to pass between ProductPage and FilterComponent anymore. The addition is to declare a reset event inside your FilterComponent.

handler.on('clearFilters', () => value = '')

Like this:

<script>
    import { check } from '@vincjo/datatables';

    export let handler;
    export let id;
    export let defaultSelectedText;
    export let options;
    export let filterBy = null;

    let value = '';

    function filter() { [...] }

    handler.on('clearFilters', () => value = '')
</script>

<select class="form-select" {id} bind:value on:change={filter}>
   [...]
</select>

It tells handler to set value as an empty string each time handler.clearFilters() is executed in ProductPage. Will work for each FilterComponent inheriting from the same Datahandler instance.

The reset should work properly. Please let me know if the problem persists

I updated the example to illustrate: https://vincjo.fr/datatables/test/clear-filters

ghost commented 12 months ago

@vincjo Thank you! It works beautifully!