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
54 stars 6 forks source link

TaskEdit closeAction:destroy breaks scheduler #8939

Closed marciogurka closed 5 months ago

marciogurka commented 7 months ago

Forum post

"Hi,

We want to configure the taskEditor with closeAction = destroy because depending on the widgets that are enabled for the specific event it should edit the height of the editor.

But when we add the param: closeaction = destroy it breaks the scheduler.

See the demo to reproduce:"

import { EventModel, ResourceModel, SchedulerPro, StringHelper } from '../../build/schedulerpro.module.js?474872';
import shared from '../_shared/shared.module.js?474872';

// Custom event model with multiple additional fields and a reconfigured default field
class ProEvent extends EventModel {
    static get fields() {
        return [
            { name : 'durationUnit', defaultValue : 'hour' },
            { name : 'order',  defaultValue : 'New order' },
            'cost',
            'contact',
            'phone'
        ];
    }
}

// Custom resource model with an additional field
class Resource extends ResourceModel {
    static get fields() {
        return [
            'type'
        ];
    }
}

const scheduler = new SchedulerPro({
    project : {
        autoLoad : true,
        loadUrl  : './data/data.json',

    // Custom model classes that have additional fields
    resourceModelClass : Resource,
    eventModelClass    : ProEvent,

    // Display the editor when data is loaded
    listeners : {
        async load() {
            // Await initial calculations
            await scheduler.project.commitAsync();

            // Show the editor with 500 ms delay
            this.setTimeout(() => scheduler.editEvent(scheduler.eventStore.first, scheduler.resourceStore.getById('weld')), 500);
        }
    }
},

appendTo   : 'container',
startDate  : new Date(2020, 3, 6),
endDate    : new Date(2020, 3, 11),
rowHeight  : 50,
barMargin  : 0,
eventStyle : null,

viewPreset : {
    base      : 'hourAndDay',
    tickWidth : 20,
    headers   : [
        {
            unit       : 'day',
            dateFormat : 'dddd' // Monday
        },
        {
            unit       : 'hour',
            dateFormat : 'HH' // 00-23
        }
    ]
},

columns : [
    {
        text  : 'Resource',
        field : 'name',
        width : 200
    },
    {
        text   : 'Type',
        field  : 'type',
        hidden : true
    },
    {
        text   : 'Tasks',
        field  : 'events.length',
        width  : 70,
        align  : 'right',
        editor : false
    },
    {
        text      : 'Allocation',
        type      : 'percent',
        editor    : false,
        sortable  : false,
        groupable : false,
        align     : 'center',
        renderer({ record : resource }) {
            // Detect overlap
            if (resource.events.some(task =>
                task.isScheduled && !scheduler.eventStore.isDateRangeAvailable(task.startDate, task.endDate, task, resource))
            ) {
                return {
                    tag       : 'i',
                    className : 'b-fa b-fa-exclamation-triangle',
                    style     : 'color : red',
                    dataset   : {
                        btip : 'Overlap!'
                    }
                };
            }

            // Calculate allocation
            const
                duration   = resource.events.reduce((total, task) => total += task.duration, 0),
                allocation = Math.round((duration / 40) * 100);

            return this.defaultRenderer({ value : allocation });
        }
    }
],

features : {
    group : 'type',

    percentBar : true,

    taskEdit : {
        // Change editor title
        editorConfig : {
            title : 'Edit ',
closeAction: 'destroy',

        },

        // Customize its contents
        items : {
            generalTab : {
                // Customize the title of the general tab
                title : 'Common',
                items : {
                    // Hide the end date field
                    endDateField : null,
                    // Add a field to edit order name
                    orderField   : {
                        type   : 'text',
                        name   : 'order',
                        label  : 'Order',
                        // Place after name field
                        weight : 150
                    },
                    priority : {
                        type       : 'radiogroup',
                        name       : 'priority',
                        label      : 'Priority',
                        labelWidth : '6em',
                        flex       : '1 0 100%',
                        weight     : 150,  // Place before resources field
                        options    : {
                            high : 'High',
                            med  : 'Medium',
                            low  : 'Low'
                        }
                    }
                }
            },
            // Hide the notes tab
            notesTab  : null,
            // Add a custom tab with some fields
            customTab : {
                defaults : {
                    labelWidth : '5em'
                },
                title : 'Job',
                items : {
                    noteField : {
                        type  : 'text',
                        name  : 'note',
                        label : 'Note'
                    },
                    costField : {
                        type  : 'number',
                        name  : 'cost',
                        label : 'Cost'
                    },
                    contactField : {
                        type  : 'text',
                        name  : 'contact',
                        label : 'Contact'
                    },
                    phoneField : {
                        type  : 'text',
                        name  : 'phone',
                        label : 'Phone'
                    }
                },
                // Show it after generalTab, which has weight 100
                weight : 150
            }
        }
    }
},

timeAxis : {
    filters : tick => tick.startDate.getHours() > 6 && tick.startDate.getHours() < 17
},

eventRenderer({ eventRecord : task, resourceRecord, renderData }) {
    renderData.eventColor = {
        'Order 1'   : '#ffefd5',
        'Order 2'   : '#87cefa',
        'New order' : '#ffa500'
    }[task.order];

    // Highlight overlapping tasks within a resource
    if (!scheduler.eventStore.isDateRangeAvailable(task.startDate, task.endDate, task, resourceRecord)) {
        renderData.eventColor = '#f08080';
    }

    renderData.style = `border-color: ${renderData.eventColor}; color: ${renderData.eventColor}`;

    return [
        {
            className : 'desc',
            children  : [
                StringHelper.encodeHtml(task.name),
                {
                    tag       : 'div',
                    className : 'order',
                    html      : `${task.order}, ${task.percentDone}%`
                }
            ]
        },
        task.note ? {
            tag       : 'i',
            className : 'b-fa b-fa-sticky-note b-last',
            dataset   : {
                btip : task.note
            }
        } : null
    ];
}
});

Removing the closeAction : 'destroy' from the editor config makes all work correctly, with that option, an error appears

Uncaught (in promise) TypeError: editor.beforeCancel is not a function

ExtAnimal commented 7 months ago

It’s not valid.

the Editor component is persistent. It is created once and then used.

isglass commented 7 months ago

We should hide that config in docs