Our blazing fast Grid component built with pure JavaScript


Post by bensullivan »

Hi

Is it possible to have rows in a grid, with each row having three columns, and each column cell containing a combo and when a value is selected in a combo, the other two combos are locally filtered with entries relevant to the value selected in the first combo?

The cascading combos example you have doesn't appear to operate within a grid...

Thanks!

Ben

Post by sergey.maltsev »

Hi, bensullivan!

You could check this sample code.
Changing filter combo affects on Room dropdown combo.
import '../_shared/shared.js'; // not required, our example styling etc.
import Grid from '../../lib/Grid/view/Grid.js';
import '../../lib/Grid/column/NumberColumn.js';
import Store from '../../lib/Common/data/Store.js';
import '../../lib/Grid/column/PercentColumn.js';

const roomStore = new Store({
    idField : 'value',
    data    : [
        { value : 1, text : 'One' },
        { value : 2, text : 'Two' },
        { value : 3, text : 'Three' },
        { value : 11, text : 'Eleven' },
        { value : 12, text : 'Twelve' },
        { value : 13, text : 'Thirteen' }
    ]
});

const filterStore = new Store({
    idField : 'min',
    data    : [
        { min : 1, max : 9, text : 'Filter room 1-9' },
        { min : 10, max : 19, text : 'Filter room 10-19' }
    ]
});

const myFields = [
    'person',
    { name : 'room', type : 'number' },
    { name : 'filter', type : 'number' }
];

new Grid({
    appendTo : 'container',
    columns  : [
        {
            field  : 'filter',
            text   : 'Filter',
            editor : {
                type      : 'dropdown',
                store     : filterStore,
                listeners : {
                    change : onFilterComboSelect
                }
            },
            renderer({ record }) {
                const filter = filterStore.getById(record.filter);
                return filter ? filter.text : record.filter;
            },
            width : 200
        },

        {
            field  : 'room',
            text   : 'Room',
            editor : {
                type  : 'dropdown',
                store : roomStore
            },
            renderer({ record }) {
                const room = roomStore.getById(record.room);
                return room ? room.text : record.room;
            },
            width : 200
        },
        {
            field : 'person',
            text  : 'Person',
            width : 100
        }

    ],
    store : new Store({
        fields : myFields,
        data   : [{ room : 1, filter : 1 }]
    })
});

function onFilterComboSelect({ source: combo }) {
    const filter = combo.record;
    roomStore.filter(room => room.value >= filter.min && room.value <= filter.max);
}

Post by bensullivan »

Thankyou!!

Post by bensullivan »

Hi Sergey

I used your code to build the following:
import {Grid, WidgetHelper, Store} from './build/grid.module.js';

let column = 2;

const myFields = [
    {name: 'person'},
    {name: 'role'},
    {name: 'team'}
];

const personStore = new Store({
    idField: 'value',
    data : [
        { text : 'Select...' },
        { value: 'PER-1', text : 'Bilbo Baggins' },
        { value: 'PER-2', text : 'Samwise Gamjee' },
        { value: 'PER-3', text : 'Peregrin Took' }
    ]  
 });

 const roleStore = new Store({
    idField: 'value',
    data : [
        { text : 'Select...' },
        { value: 'ROL-1', text : 'Hobbit1', person: 'PER-1' },
        { value: 'ROL-2', text : 'Hobbit2', person: 'PER-2' },
        { value: 'ROL-3', text : 'Hobbit3', person: 'PER-3' }
    ]  
 });

const grid = new Grid({
    appendTo: 'target',
    features : {
        cellEdit: true,
        stripe: true
    },
    showDirty: true,
    columns: [
        { 
            field: 'person', 
            text: 'Person', 
            editor : { type : 'dropdown', store : personStore, listeners : { change : onPersonComboChange } },
            renderer({ record }) {
                const person = personStore.getById(record.person);
                return person ? person.text : record.person;
            }, 
            width: 300, 
            locked: true 
        },
        { 
            field: 'role', 
            text: 'Role', 
            editor : { type : 'dropdown', store : roleStore },
            renderer({ record }) {
                const role = roleStore.getById(record.role);
                return role ? role.text : record.role;
            }, 
            width: 300, 
            locked: true 
        },
        { field: 'team', text: 'Team', width: 150, locked: true },
        { text: '2019<br>Nov', type: 'percent', field: 'capacity1', width: 60}
    ],
    store : new Store({
        fields : myFields,
        data   : [
            {person: 'Select...', role: 'Select...', team: 'Select...', capacity1: 0}
        ]
    })
});

function onPersonComboChange({ source: combo }) {
        const filter = combo.record;
        console.log(`Selected person: ${filter.data.value}`);
        roleStore.filter(role => {
            console.log(role.data.person == filter.data.value);
            role.data.person == filter.data.value;
        });
}

WidgetHelper.append([
    {
        type     : 'button',
        ref      : 'removeButton',
        text     : 'Remove Last Month',
        color    : 'b-orange b-raised',
        icon     : 'b-fa b-fa-minus',
        tooltip  : 'Remove Last Month',
        onAction : () => grid.columns.count > 1 && grid.columns.last.remove()
    },
    {
        type     : 'button',
        ref      : 'addButton',
        text     : 'Add Month',
        color    : 'b-green b-raised',
        icon     : 'b-fa b-fa-plus',
        tooltip  : 'Add new month',
        onAction : () => {
            const fieldName = `capacity${column++}`;
            myFields.push({ name : fieldName, type : 'percent', text: 'Dec', width: 60 });

            const store = new Store({
                fields : myFields,
                data   : grid.store.records.map(r => r.data)
            });

            grid.store = store;
            grid.refreshRows();
            grid.columns.add({ text : 'Dec', type : 'percent', field : fieldName, width : 100 });
            // grid.store.add({ id : grid.store.count + 1, [fieldName] : column });
            
            
            // grid.columns.add({ text: 'Dec', type: 'percent', field: 'capacity2', width: 60});
        }
    }  
], { insertFirst : document.getElementById('gridButtons') || document.body });
For some reason, the listener is firing for both person and role combos and I don' understand why. Also, the roleStore.filter call in the listener does not appear to be filtering the role dropdown contents after the listener finishes execution. Can you see what I'm doing wrong?

Thanks!

Ben

Post by bensullivan »

I seemed to get it working with this code:
import {Grid, Store} from './build/grid.module.js';

const personStore = new Store({
    idField : 'personId',
    data    : [
        { personId : 'PER-1', text : 'Bilbo' },
        { personId : 'PER-2', text : 'Samwise' },
        { personId : 'PER-3', text : 'Peregrine' }
    ]
});

const roleStore = new Store({
    idField : 'roleId',
    data    : [
        { roleId : 'ROL-1', text : 'Farmer', personId: 'PER-1'},
        { roleId : 'ROL-2', text : 'Cook', personId: 'PER-3' }
    ]
});

const myFields = [
    'team',
    { name : 'person' },
    { name : 'role' }
];

new Grid({
    appendTo : 'target',
    columns  : [
        {
            field  : 'role',
            text   : 'Role',
            editor : {
                type      : 'dropdown',
                store     : roleStore,
                listeners : {
                    change : onRoleComboChange
                }
            },
            renderer({ record }) {
                const role = roleStore.getById(record.role);
                return role ? role.text : record.role;
            },
            width : 200
        },
        {
            field  : 'person',
            text   : 'Person',
            editor : {
                type  : 'dropdown',
                store : personStore
            },
            renderer({ record }) {
                const person = personStore.getById(record.person);
                return person ? person.text : record.person;
            },
            width : 200
        },
        {
            field : 'team',
            text  : 'Team',
            width : 100
        }

    ],
    store : new Store({
        fields : myFields,
        data   : [{ role : 'Cook' }]
    })
});

// function onFilterComboSelect({ source: combo }) {
function onRoleComboChange({ source: roleCombo }) {
    const filterRole = roleCombo.record;
    personStore.filter(person => person.personId == filterRole.personId);
}
Is it possible to clear a column dropdown editor from a listener function?
Is it possible to clear a dropdown from in the combo itself like on the cascading combo example?
Can a column dropdown editor be activated without having to double click on the cell?

Thanks

Ben

Post by sergey.maltsev »

Hi!

You can update personStore whenever you want and this will update dropdown list when editor is shown.

You can start editing with grid.startEditing() method.
https://www.bryntum.com/docs/grid/#Grid/view/Grid#function-startEditing

To show dropdown just call inputField.showPicker()
https://www.bryntum.com/docs/grid/#Common/widget/PickerField#function-showPicker

This code clears personStore and shows empty dropdown.
if (grid.startEditing({
    record : grid.store.first,
    field  : 'person' })) {
    personStore.clear();
    grid.features.cellEdit.editorContext.editor.inputField.showPicker();
}

Post by bensullivan »

Is it possible to configure a grid such that the editing of a cell is initiated by a single click instead of a double click?

I'm guessing this might interfere with the fact that a row in a grid is selected by a single click?

Thanks

Ben

Post by sergey.maltsev »

Hi!

Please next time create new post for each separate question.

You can use cellClick event to process single click with your own way.
https://www.bryntum.com/docs/grid/#Grid/view/mixin/GridElementEvents#event-cellClick
grid.on('cellClick', ({ source, record, cellSelector, cellElement, target, event }) => console.log('click'))
More info on using events can be found here
https://www.bryntum.com/docs/grid/#Common/mixin/Events

Also on touch devices if you tap on selected cell again this will open editor.

Post by bensullivan »

Hi Sergey

Apologies for not creating a new post and thanks for the reply.

Cheers

Ben

Post by sergey.maltsev »

Hi!

You are welcome!

Post Reply