Smart.GanttChart - Editing
Task Editor
Smart.GanttChart's tasks can be edited via the window editor. The editor represents a Window component that appears when the user double clicks on a task or a connection inside the Timeline.
-
Task Editing - the window editor allows the user to quickly edit the clicked task. The taskColumns property is used to display the value of the properties of the tasks and determines how they are going to be edited. By default each column that represents a task property has it's own editor that appears inside the window when oepened. However property editors can be replaced with a custom editors. In order to do that the user has to define three callback function for the target task property in the taskColumns array:
-
customEditor - a callback that accepts a function which must return an HTML element that represents the custom editor for the column. The callback has two arguments:
- label - the name of the property that is being edited (e.g. 'duration')
- value - the current value of the property that is being edited (e.g. 8)
In the example below we want to display the 'duration' of the tasks and set a custom editor for that property:
window.onload = function () { const gantt = document.querySelector('smart-gantt-chart'); gantt.taskColumns = [ { label: 'Duration (Hours)', value: 'duration', formatFunction: (date) => parseInt(date), customEditor: function (label, value) { let fragment = document.createDocumentFragment(), customEditorLabel = document.createElement('label'), dropDownList = document.createElement('smart-drop-down-list'); customEditorLabel.innerHTML = 'Duration'; dropDownList.dropDownAppendTo = 'body'; dropDownList.dataSource = [4, 8, 12]; fragment.appendChild(customEditorLabel); fragment.appendChild(dropDownList); return fragment; } }]; })
NOTE: If the callback is not defined the default editor will be used instead. The default editor for 'duration' is a numeric input.
-
setCustomEditorValue - a callback that accepts a function which sets the value of the custom editor. It accepts three arguments:
- editor - the actual editor that was created from the customEditor callback.
- label - the name of the task property that is being edited (e.g. 'duration')
- value - the current value of the property that is being edited (e.g. '8')
... setCustomEditorValue: function (editor, label, value) { const dropDownList = editor.querySelector('smart-drop-down-list'); dropDownList.select(value.toString()); }
NOTE: If the callback is not defined the editor will be remain unset.
-
getCustomEditorValue - a callback that should return the value of the editor in the appropriate format which in the case of 'duration' is number. It accepts one argument:
- editor - the actual editor that was created from the customEditor callback.
... getCustomEditorValue: function (editor) { const dropDownList = editor.querySelector('smart-drop-down-list'); return dropDownList.selectedValues[0]; }
NOTE: If the callback is not defined editing will not be successful because the element does not know what the value of the custom editor is.
-
customEditor - a callback that accepts a function which must return an HTML element that represents the custom editor for the column. The callback has two arguments:
The editor will appear in the Window when it's opened. In the example a DropDownList component is created in order to set a specific duration of the edited task.
Note: The demo used in this section is available on the website: gantt chart custom task editor
Connection Editor
The window editor is also used to delete connections between tasks. When the user double clicks on a connection the window editor opens and allows to delete the connection.
Custom Window Editor
The window editor can be completely customized using the element's popupWindowCustomizationFunction property. The property accepts a callback with three arguments:- target - the window instance that is going to be customized.
- type - the type of window that is going to be customized (e.g. 'task', 'connection')
- index - the index of the task or the id of a connection. ( depending on the target that was clicked )
const gantt = document.querySelector('smart-gantt-chart'); let editedTaskIndex, taskLabel, description, dayPicker, monthPicker, yearPicker, dayIncrementBtn, dayDecrementBtn, dayInput, totalDate, deleteBtn, cancelBtn, saveBtn; gantt.popupWindowCustomizationFunction = function (target, type, taskIndex) { const targetTask = gantt.tasks[taskIndex]; if (type === 'task' && targetTask) { let addListeners; editedTaskIndex = taskIndex; //Hide the header target.headerPosition = 'none'; target.footerPosition = 'none'; //Create the content if (!document.getElementById('taskLabel')) { addListeners = true; target.clear(); target.appendChild(document.getElementById('myTemplate').content); } taskLabel = document.getElementById('taskLabel'); description = document.getElementById('description'); dayPicker = document.getElementById('dayPicker'); monthPicker = document.getElementById('monthPicker'); yearPicker = document.getElementById('yearPicker'); dayIncrementBtn = document.getElementById('dayIncrementBtn'); dayDecrementBtn = document.getElementById('dayDecrementBtn'); dayInput = document.getElementById('dayInput'); totalDate = document.getElementById('totalDate'); deleteBtn = document.getElementById('deleteBtn'); cancelBtn = document.getElementById('cancelBtn'); saveBtn = document.getElementById('saveBtn'); //Configure the content const dateStart = targetTask.dateStart, dateEnd = targetTask.dateEnd; if (!dateStart || !dateEnd) { taskLabel.innerHTML = ''; } else { const dayFormat = ['2-digit', 'numeric'][gantt.dayFormat] || 'numeric'; taskLabel.innerHTML = dateStart.toLocaleDateString(gantt.locale, { day: dayFormat, month: gantt.monthFormat, year: gantt.yearFormat }) + ' - ' + dateEnd.toLocaleDateString(gantt.locale, { day: dayFormat, month: gantt.monthFormat, year: gantt.yearFormat }); } description.value = targetTask.label; dayPicker.value = dateStart.getDate(); monthPicker.value = dateStart.getMonth(); yearPicker.value = dateStart.getFullYear(); dayInput.value = targetTask.duration.toString(); totalDate.innerHTML = targetTask.dateEnd.toDateString(); if (addListeners) { dayIncrementBtn.addEventListener('click', function () { dayInput.value = (Math.min(31, (parseInt(dayInput.value) || 0) + 1)).toString(); updateTotalDate(); }); dayDecrementBtn.addEventListener('click', function () { dayInput.value = Math.max(1, (parseInt(dayInput.value) || 0) - 1).toString(); updateTotalDate(); }); deleteBtn.addEventListener('click', deleteTask); cancelBtn.addEventListener('click', cancelTask); saveBtn.addEventListener('click', saveTask); } } };
The popupWindowCustomizationFunction function is called every time the window is opened.
Then we define the functions that will apply the different actions that corresponding to the clicked button
... function updateTotalDate() { let newDateEnd = new Date(parseInt(yearPicker.value), parseInt(monthPicker.value), parseInt(dayPicker.value)); newDateEnd.setDate(newDateEnd.getDate() + parseInt(dayInput.value)); if (isNaN(newDateEnd.getTime())) { totalDate.innerHTML = ''; return; } totalDate.innerHTML = newDateEnd.toDateString(); } function deleteTask() { gantt.removeTask(editedTaskIndex); gantt.closeWindow(); editedTaskIndex = undefined; }; function cancelTask() { gantt.closeWindow(); }; function saveTask() { let dateStart = new Date(parseInt(yearPicker.value), parseInt(monthPicker.value), parseInt(dayPicker.value)), duration = parseInt(dayInput.value); gantt.updateTask(editedTaskIndex, { label: description.value, dateStart: dateStart, duration: duration }); gantt.closeWindow(); editedTaskIndex = undefined; };
In the current example three buttons are used to save the changed to the clicked task via the updateTask method, remove the task via the removeTask method and cancel which cancels the changes and closes the window via the closeWindow method.
Note: The demo used in this section is available on the website: Link
Editor Window Methods
There are two methods that are documented in the API of the GanttChart element-
openWindow - opens the editing window. The method accepts one argument - the id/index/path of a task or the id of a connection. If the argument is correct the corresponding editor window will open.
const gantt = document.querySelector('smart-gantt-chart'); gantt.openWindow(0);
Calling the openWindow with argument '0' will open the Window to edit the Task with index 0 ( the first task ).
-
closeWindow - closes all opened editor windows.
const gantt = document.querySelector('smart-gantt-chart'); gantt.closeWindow();
Editor Window Events
-
opening - the opening action of the editor window can be prevented by adding an event listener to the opening event of the GanttChart element which is fired when the editor window is about to open.
ganttChart.addEventListener('opening', function (event) { event.preventDefault(); })
-
open - fired when the editor window is opened.
ganttChart.addEventListener('open', function (event) { //Do something here... })
-
close - fired when the editor window is closed.
ganttChart.addEventListener('open', function (event) { //Do something here... })
-
closing - simiral to the opening event, closing is fired before the window is closed and the action can also be prevented.
ganttChart.addEventListener('closing', function (event) { event.preventDefault(); })
Keyboard Navigation
Keyboard navigation inside the Window is enabled by default when the window is focused.Key | Action |
---|---|
Escape | Pressing the 'Escape' key will close the window. |
Tab | Pressing Tab will change the focus of the different elements inside the window. |
Control + Arrow Up/Down/Left/Right | Pressing an Arrow key while Control is pressed allows to drag the window in the direction of the arrow. |