vincjo / datatables

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

Multiple advanced filters with the same filter function not working together #48

Closed JakeBriscoe closed 1 year ago

JakeBriscoe commented 1 year ago

I have tag categories that are each their own column, for example department and job level. I want to have an advanced filter for each column and have the filters work together, for example (department = product OR design) AND (job level = senior). If I manually define the filters with unique filter functions they work as expected. If I give them the same filter function or I create them dynamically (which I need to do) they work individually but not together with the other filters, it's the same behaviour as removing the other filters first.

Works ✅

const departmentFilter = handler.createAdvancedFilter((row) =>
    row.tags.filter((x) => x.tagCategoryId === 1).map((x) => x.tagId),
);
const levelFilter = handler.createAdvancedFilter((row) =>
    row.tags.filter((x) => x.tagCategoryId === 2).map((x) => x.tagId),
);

Doesn't work ❌

const filterFns = [1, 2].map((tagCategory) =>
    handler.createAdvancedFilter((row) =>
    row.tags.filter((x) => x.tagCategoryId === tagCategory).map((x) => x.tagId),
    ),
);

Doesn't work ❌

const departmentFilter = handler.createAdvancedFilter((row) =>
    row.tags.map((x) => x.tagId),
);
const levelFilter = handler.createAdvancedFilter((row) =>
    row.tags.map((x) => x.tagId),
);
vincjo commented 1 year ago

If I'm not wrong, in your example you use the same callback to create 2 advanced filter.

handler.createAdvancedFilter(callback) // x2

To have distinct advanced filters using the same callback function, callback.toString() must be different strings.

it may seem a bit counter-intuitive: callback.toString() is used to identify a unique filter. When this filter changes, the handler is able to update it without duplicating it.

Should work ✅

const departmentFilter = handler.createAdvancedFilter((row) =>
    row.tags.map((x) => x.tagId)
);
const levelFilter = handler.createAdvancedFilter((row) =>
    row.tags.map((y) => y.tagId)
);
JakeBriscoe commented 1 year ago

Ahh thank you! To generate a unique .toString() inside a loop I made a utility function that returns the callback function and overwrites the .toString() method

const createFilterCallback = (tagCategoryId) => {
    const callback = (row) =>
        row.tags.filter((x) => x.tagCategoryId === tagCategoryId).map((x) => x.tagId);
    callback.toString = () =>
        `function(row) { return row.tags.filter((x) => x.tagCategoryId === ${tagCategoryId}).map((x) => x.tagId); }`;
    return callback;
};