vincjo / datatables

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

Select Option Filter With Different Value Types #42

Closed ghost closed 1 year ago

ghost commented 1 year ago

Hello, my database has published_at field that contains either date or null. If it's null, then I displayed it in Svelte Datatables by string "Unpublished". If it's not null then I just displayed the date itself.

Now I want to filter if it's published or not. It's easy for the null value because I just need to pass "Unpublished" for the select option value, but I have no idea how for the date value since every date is different. Right now I have a cheesy workaround, since every date that I displayed contains a comma, I set the select option value for not null to comma and that works, but I don't think this is the best? Does Svelte Datatables have function or solution for this kind of filter?

This is my code right now:

TableFilterSelect :

<script>
    export let handler;
    export let id;
    export let defaultSelectedText;
    export let options;
    export let filterBy = null;

    let value = '';
</script>

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

Page :

<TableFilterSelect {handler} id="published_at" filterBy="published_at" defaultSelectedText="Select Published" options={[{"value": ",", "text": "Yes"}, {"value": "Unpublished", "text": "No"}]} />

Thank you.

vincjo commented 1 year ago

Hello, If I understand correctly you have to filter a column on isNull / isNotNull parameters. The filter method can have a 3rd param which defines a comparator. Doc: https://vincjo.fr/datatables/examples/advanced-filters

<script>
    import { check } from '@vincjo/datatables'
    export let handler;
    export let id;
    export let defaultSelectedText;
    export let filterBy = null;

    let value = '';

    const filter = () => {
        if (!value) {
             // This will remove filter on this column if selected option is null/undefined
             return handler.filter(null, filterBy)
        }
        // this will filter "isNull" or "isNotNull" 
        return handler.filter('aDefaultStringWhichIsUseless', filterBy, check[value])
    }
</script>

<select class="form-select" {id} bind:value on:change={filter}>
    <option value="" disabled="{value === ''}" hidden="{value === ''}">{defaultSelectedText}</option>
    <option value="isNull">Not Published</option>
    <option value="isNotNull">Published</option>
</select>
ghost commented 1 year ago

@vincjo I can't express how much I appreciate your help! Your solutions works for me. At first, my published_at value isn't null or not null, but rather date or Unpublished. This is because I need to format the date from backend, but then I change the formating part to front-end using dayjs, thus enabling null and not null.

I do need to tweak the code a bit because I have other select that contains value like 1 or 0, etc. My final code using your help looks like this:

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

This will enable both null and not null select, and at the same time other kinds of value of select.