Premium support for our pure JavaScript UI components


Post by mats »

Then you need to apply it to the filter field instead:

const 
yourColumn = grid.columns.getAt(2),
field = grid.features.filterBar.getColumnFilterField(yourColumn)
field.store.data = yourNewData;

Post by jandresampaio »

That code works only if the column is not hidden. then I would have to catch the show event to set the filter values.
This seems a bug, where the filter bar is out of sync with the rows values. If you hide and show the column the filter values will be updated accordingly.


Post by alex.l »

That code works only if the column is not hidden. then I would have to catch the show event to set the filter values.

Dynamic data for filterBar combos are not supported out of the box, it should be implemented manually. There are many ways how to achieve this but it depends on your use case. Sorry, we cannot give you a perfect solution if we don't know what do you want to achieve.
Another way is to keep the links to store instances (set a variable when you create filterBar, as example) in some scope to always have access to it and update data independent of field visibility.
Try to attach your solution and describe your problem, we will be glad to help.

This seems a bug, where the filter bar is out of sync with the rows values

Could you please provide steps to reproduce, actual and expected results? I didn't get what is the bug there.

All the best,
Alex


Post by jandresampaio »

You don't know what I want to achieve? Did you read this forum post?


Post by saki »

I think that the whole problem starts with the attempt to have same instance of combo for filterBar and for column editor. This is not possible because these are always create as separate instances. Nevertheless, we can use the same data for both initially and we can also update both with the same data at runtime but we always have to consider them as two.

Here is my testing code, which is modified paged grid example (you can replace app.js content of that example with the following content):

import '../_shared/shared.js';
import '../../lib/Core/helper/DomHelper.js';
import '../../lib/Grid/column/PercentColumn.js';
import '../../lib/Grid/column/NumberColumn.js';
import Grid from '../../lib/Grid/view/Grid.js';
import DataGenerator from '../../lib/Core/helper/util/DataGenerator.js';
import AjaxStore from '../../lib/Core/data/AjaxStore.js';
import CollectionFilter from '../../lib/Core/util/CollectionFilter.js';
import '../../lib/Core/widget/PagingToolbar.js';
import BrowserHelper from '../../lib/Core/helper/BrowserHelper.js';
import AjaxHelper from '../../lib/Core/helper/AjaxHelper.js';
import GridRowModel from '../../lib/Grid/data/GridRowModel.js';
import Toast from '../../lib/Core/widget/Toast.js';

let
    rowCount = BrowserHelper.searchParam('rowCount') || 250,
    pageSize = BrowserHelper.searchParam('pageSize') || 25,
    currentPage = 1,
    data = [];

// This intercepts AjaxHelper.fetch calls and calls AjaxHelper's fetch success handling
// method using a mocked up Fetch Response object with the returned object assigned
// over its default properties. Here we just return responseText with the generated data.
AjaxHelper.mockUrl('/pagedMockUrl', (url, params) => {
    const
        page     = parseInt(params.page, 10),
        pageSize = parseInt(params.pageSize, 10),
        startIdx = (page - 1) * pageSize;

    if (data.length !== rowCount) {
        data = DataGenerator.generateData(
            rowCount,
            null,
            1
        );
    }

    let returnedData = data.slice();

    // Filter the data if filter parameter is passed
    if (params.filter) {
        returnedData = returnedData.filter(
            CollectionFilter.generateFiltersFunction(
                JSON.parse(params.filter).map(f => {
                    f.property = f.field;
                    return new CollectionFilter(f);
                })
            )
        );
    }

    // Sort the data if sort parameter is passed
    if (params.sort) {
        returnedData.sort(store.createSorterFn(JSON.parse(params.sort)));
    }

    return {
        responseText : JSON.stringify({
            success : true,
            total   : returnedData.length,
            data    : returnedData.slice(startIdx, startIdx + pageSize)
        })
    };
});

const cityCombo = {
    type : 'combo',

    items : [
        { value : 'medium', text : 'Medium' },
        { value : 'large',  text : 'Large' }
    ]
};

const cityComboData1 = [
    { value : 'medium', text : 'Medium' },
    { value : 'large',  text : 'Large' }
];

const
    maxCount    = 1000,
    minCount    = 10,
    store = new AjaxStore({
        modelClass      : GridRowModel,
        readUrl         : '/pagedMockUrl',
        pageParamName   : 'page',
        sortParamName   : 'sort',
        filterParamName : 'filter',
        pageSize        : pageSize,
        autoLoad        : true
    });

const grid = new Grid({
    appendTo : 'container',

    store,

    features : {
        filterBar : true
    },

    columns : [
        { text : '#', type : 'number', width : 80, field : 'id' },
        {
            text  : 'First name',
            field : 'firstName',
            flex  : 1,
            id    : 'firstName',

            editor : {
                type  : 'combo',
                items : cityComboData1
            },
            filterable : {
                filterField : {
                    type        : 'combo',
                    multiSelect : true,
                    items       : cityComboData1
                }
            }
        },
        { text : 'Surname', field : 'surName', flex : 1 },
        { text : 'Score', field : 'score', flex : 1, type : 'number' },
        { text : 'Rank', field : 'rank', flex : 1, type : 'number' },
        { text : 'Percent', field : 'percent', width : 150, type : 'percent' }
    ],

    tbar : [
        {
            type     : 'button',
            ref      : 'getButton',
            color    : 'b-blue',
            text     : 'Store state',
            icon     : 'b-fa b-fa-box',
            tooltip  : 'Stores the grids current state in localStorage',
            onAction : () => {
                // grid.state fetches the grids current state
                const state = grid.state;
                localStorage.setItem('b-grid-state', JSON.stringify(state));

                grid.widgetMap.setButton.enable();
                grid.widgetMap.clearButton.enable();

                Toast.show('State stored in localStorage');
            }
        },
        {
            type     : 'button',
            ref      : 'setButton',
            color    : 'b-blue',
            icon     : 'b-fa b-fa-box-open',
            text     : 'Restore state',
            disabled : !localStorage.getItem('b-grid-state'),
            tooltip  : 'Restores the grids state from localStorage. Store it first by clicking Get state',
            onAction : () => {
                const state = JSON.parse(localStorage.getItem('b-grid-state'));
                // assigning to grid.state applies a state to the grid
                if (state) {
                    grid.state = state;
                }

                Toast.show('State restored from localStorage');
            }
        },
        {
            type     : 'button',
            ref      : 'clearButton',
            color    : 'b-red',
            icon     : 'b-fa b-fa-times',
            text     : 'Clear state',
            disabled : !localStorage.getItem('b-grid-state'),
            tooltip  : 'Clears state from localStorage',
            onAction : () => {
                localStorage.removeItem('b-grid-state');

                grid.widgetMap.setButton.disable();
                grid.widgetMap.clearButton.disable();

                Toast.show('State remove from localStorage');
            }
        }
    ],

    bbar : {
        type  : 'pagingtoolbar',
        items : {
            // Uncomment this to add an extra button
            // click : {
            //     type    : 'button',
            //     text    : 'Click me',
            //     onClick : () => console.log('Clicked button'),
            //     weight  : 1000 // append to the end of default items
            // }
        }
    }
});

const cityComboData2 = [
    { value : 'small',  text : 'Small' },
    { value : 'medium', text : 'Medium' },
    { value : 'large',  text : 'Large' }
];

const column = grid.columns.get('firstName');

const filterBarCombo = grid.features.filterBar.getColumnFilterField(column);
filterBarCombo.store.data = cityComboData2;

const columnEditor = column.editor;
columnEditor.store.data = cityComboData2;

Here we create both combos with initial cityComboData1 array and then, at the end of the file we get a hold of both combos, one-by-one and replace their data with the new ones from cityComboData2.

I hope it helps.


Post by jandresampaio »

I understood that this would work but only if the column is visible when rendering the view. If the firstName column is first hidden and then you switch it to visible in column picker, the datasource will not be updated.

That's why I've mentioned this earlier:

That code works only if the column is not hidden. then I would have to catch the show event to set the filter values.


Post by saki »

Yes, an update logic would have to be triggered on column show and a test of column visibility needs to be added before we attempt to update the editor or filter combo stores. This is not done automatically so it needs to be implemented on the application level.


Post Reply