bryntum / support

An issues-only repository for the Bryntum project management component suite which includes powerful Grid, Scheduler, Calendar, Kanban Task Board and Gantt chart components all built in pure JS / CSS / TypeScript
https://www.bryntum.com
55 stars 6 forks source link

showPicker on focusIn, shows not ready to use picker #10276

Open marciogurka opened 1 month ago

marciogurka commented 1 month ago

Forum post

"Hi there,

We're coming across a strange issue with the combo editor.

We want the combo's picker to open automatically upon clicking on the editor. We have been able to accomplish this by using a 'focusIn' event handler with a call to 'toWidget.showPicker()'.

The strange thing is that when you go down to the following row and click on the combo editor, it opens the picker but the filters have not cleared from the previous editor.

I have been able to reproduce this in one of your Examples with code I have attached below.

Here are the repro steps:

Code to repro:

import { Gantt, ProjectModel, AsyncHelper, PresetManager, ProjectGenerator } from '../../build/gantt.module.js?480175';
import shared from '../_shared/shared.module.js?480175';

const
    toggleCustom  = show => {
        taskCountField.hidden = projectSizeField.hidden = !show;
    },
    applyPreset   = count => {
        toggleCustom(false);
        projectSizeField.value = 50;
        taskCountField.value = count;
        gantt.generateDataset();
    };

PresetManager.registerPreset('threeMonths', {
    name            : '3 months',
    base            : 'weekAndDayLetter',
    tickSize        : 20,
    defaultSpan     : 3,
    defaultSpanUnit : 'month'
});

let busy = false;

const gantt = new Gantt({
    appendTo : 'container',

emptyText : '',

dependencyIdField : 'sequenceNumber',

columns : [
    { type : 'name', field : 'name', text : 'Name', width : 200 },
    { type : 'startdate', text : 'Start date' },
    { text: 'Combo Example',
    editor: {
        type: 'combo',
displayField: 'Name',
valueField: 'id',
items: [
    {"Name": "A", id: "ad45c242-ed55-40b2-816e-13bc7c781c72"},
    {"Name": "B", id: "b6fb319c-2924-4c31-bd5b-19ce610f3a4f"},
    {"Name": "C", id: "c690f3fd-73ca-41b6-abe5-9665a26f1500"},
    {"Name": "D", id: "d68b6637-70c1-4574-b188-dd39ac66f895"},
    {"Name": "E", id: "1f064b47-a092-41f0-b1d8-efe29c66fd8e"}
],
listeners: {
                focusIn: function (a) {
                                a.toWidget.showPicker();
                },
}
        }},
        { type : 'duration', text : 'Duration' }
    ],

columnLines : false,

// If you try approach B or C below you need to define a project here
// project : {
//     taskStore       : { useRawData : true },
//     dependencyStore : { useRawData : true }
// },

// hide data generation
async generateDataset(count = taskCountField.value) {
    // Bail out if we are already generating a dataset (it is async)
    if (busy) {
        return;
    }

    busy = true;

    if (count > 1000) {
        gantt.mask('Generating tasks');
    }

    // Required to allow browser to update DOM before task generation starts
    await AsyncHelper.sleep(100);

    const config = await ProjectGenerator.generateAsync(count, projectSizeField.value);

    // Required to allow browser to update DOM before calculations starts
    await AsyncHelper.sleep(10);

    //
    // Alternative approaches that should have similar performance:
    //

    // A) Replace entire project with a new project
    gantt.project?.destroy();

    gantt.project = new ProjectModel({
        autoSetConstraints : true,
        // The `useRawData` settings below speeds record creation up a bit by not cloning the raw data objects,
        // instead uses them directly as is
        taskStore          : { useRawData : true },
        dependencyStore    : { useRawData : true },
        ...config
    });

    gantt.startDate = gantt.project.startDate;

    if (count > 1000) {
        gantt.unmask();
    }

    // B) Replace store data per store
    // gantt.taskStore.data = config.tasksData;
    // gantt.dependencyStore.data = config.dependenciesData;
    // C) Replace store data via project
    // gantt.project.loadInlineData(config);

    gantt.project.on({
        dataReady() {
            busy = false;
        }
    });
},
// end hide

// hide toolbar settings
tbar : [
    'Presets',
    {
        type        : 'buttongroup',
        toggleGroup : true,
        items       : [
            {
                text    : '1K tasks',
                pressed : true,
                ref     : '1kButton',
                tasks   : 1000
            },
            {
                text  : '5K tasks',
                ref   : '5kButton',
                tasks : 5000
            },
            {
                text  : '10K tasks',
                ref   : '10kButton',
                tasks : 10000
            },
            {
                text : 'Custom',
                ref  : 'customButton',
                onClick() {
                    toggleCustom(true);
                }
            }
        ],
        onClick({ source : button }) {
            if (button.tasks) {
                applyPreset(button.tasks);
            }
        }
    },
    {
        type       : 'number',
        ref        : 'taskCountField',
        label      : 'Tasks',
        tooltip    : 'Enter number of tasks to generate and press [ENTER]. Tasks are divided into blocks of ten',
        value      : 1000,
        min        : 10,
        max        : 10000,
        width      : 'auto',
        inputWidth : '5em',
        step       : 10,
        hidden     : true,
        onChange({ userAction }) {
            if (userAction) {
                gantt.generateDataset();
            }
        }
    }, {
        type       : 'number',
        ref        : 'projectSizeField',
        label      : 'Project size',
        tooltip    : 'Enter number of tasks that should be connected into a "project" (multipliers of 10)',
        min        : 10,
        max        : 1000,
        value      : 50,
        width      : 'auto',
        inputWidth : '4em',
        step       : 10,
        hidden     : true,
        onChange({ userAction }) {
            if (userAction) {
                gantt.generateDataset();
            }
        }
    },
    '->',
    {
        type    : 'viewpresetcombo',
        presets : ['weekAndDay', 'dayAndMonth', 'threeMonths']
    }
]
// end hide
});

const { taskCountField, projectSizeField } = gantt.widgetMap;

gantt.generateDataset();

I have tried adding a 'focusOut' listener with a call to 'fromWidget.hidePicker()' in hopes that this would solve this issue, but it had no effect."

https://github.com/user-attachments/assets/ce0dbf83-758e-4a14-86e8-613b49ee6fbf

matsbryntse commented 1 month ago

Column definition is missing a field

marciogurka commented 1 month ago

After updating with the field to the column definition, the behavior still happens. Looks like a race condition here.

https://github.com/user-attachments/assets/c577adc3-b417-44d3-a37c-26a1510acadb