Page 1 of 1

Cascading combos in row cells

Posted: Wed Oct 02, 2019 3:34 pm
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

Re: Cascading combos in row cells

Posted: Thu Oct 03, 2019 8:54 am
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);
}

Re: Cascading combos in row cells

Posted: Thu Oct 03, 2019 8:55 am
by bensullivan
Thankyou!!

Re: Cascading combos in row cells

Posted: Mon Oct 07, 2019 9:35 am
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

Re: Cascading combos in row cells

Posted: Mon Oct 07, 2019 11:23 am
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

Re: Cascading combos in row cells

Posted: Mon Oct 07, 2019 12:00 pm
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();
}

Re: Cascading combos in row cells

Posted: Tue Oct 08, 2019 4:12 am
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

Re: Cascading combos in row cells

Posted: Tue Oct 08, 2019 5:25 am
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.

Re: Cascading combos in row cells

Posted: Tue Oct 08, 2019 5:38 am
by bensullivan
Hi Sergey

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

Cheers

Ben

Re: Cascading combos in row cells

Posted: Wed Oct 09, 2019 7:18 am
by sergey.maltsev
Hi!

You are welcome!