Here is my code. I want to add a div called gantt-control that would have some filters, undo and redo button, and maybe my legend. The problem is that when I try to add other element than the container div that have de ref attribute, I have an error (joined picture). For now, I’ve used gantt.$root.append to add new element to DOM, but i’m unsatisfied because I don’t want the control to be inside the chart, but above it.
If anyone can help, thank you :))
<template>
<div ref="ganttContainer" style="height: 80vh;"></div>
</template>
<script>
import {gantt} from 'dhtmlx-gantt';
var dateToStr = gantt.date.date_to_str(gantt.config.task_date);
var dateEditor = {type: "date", map_to: "start_date"};
var durationEditor = {type: "number", map_to: "duration", min:0, max: 100};
var stateEditor = {type: "select", options: [
{key: "Opened", label: "Opened"},
{key: "Closed", label: "Closed"},
{key: "InProgress", label: "In progress"},
{key: "Late", label: "Late"},
{key: "Unscheduled", label: "Unscheduled"}
], map_to: "state"};
let undoBtn = document.createElement('button');
undoBtn.className = 'gantt-undo';
undoBtn.textContent = 'Undo';
undoBtn.onclick = function(){
gantt.undo();
};
let redoBtn = document.createElement('button');
redoBtn.className = 'gantt-redo';
redoBtn.textContent = 'Redo';
redoBtn.onclick = function(){
gantt.redo();
};
let controlsDiv = document.createElement('div');
controlsDiv.className = 'gantt-controls';
controlsDiv.appendChild(undoBtn);
controlsDiv.appendChild(redoBtn);
let legend = document.createElement('div');
legend.className = 'gantt-legend';
legend.id = 'gantt-legend';
let header = document.createElement('header');
header.className = 'legend-head';
let h3 = document.createElement('h3');
h3.textContent = 'Legend';
header.appendChild(h3);
legend.appendChild(header);
let legendList = document.createElement('div');
legendList.className = 'legend-list';
let states = ['Opened', 'Closed', 'In progress', 'Late', 'Unscheduled', 'folder'];
let descriptions = ['Opened issues', 'Closed issues', 'In progress', 'Late issues', 'Unscheduled', 'Parent'];
for (let i = 0; i < states.length; i++) {
let row = document.createElement('div');
row.className = 'legend-row';
let label = document.createElement('div');
label.className = 'legend-label ' + states[i].toLowerCase().replace(' ', '-');
let description = document.createElement('div');
description.textContent = descriptions[i];
row.appendChild(label);
row.appendChild(description);
legendList.appendChild(row);
}
legend.appendChild(legendList);
var daysStyle = function(date){
var dateToStr = gantt.date.date_to_str("%D");
if (dateToStr(date) == "Sun"||dateToStr(date) == "Sat") return "weekend";
return "";
};
export default {
props: {
tasks: {
type: Object,
default () {
return {data: [], links: []}
}
}
},
mounted: function () {
gantt.plugins({
marker: true,
multiselect: true ,
tooltip: true ,
undo: true
});
gantt.config.undo = true;
gantt.config.redo = true;
gantt.config.date_format = "%Y-%m-%d";
gantt.config.scales = [
{unit: "month", step: 1, format: "%F, %Y"},
{unit: "day", step: 1, format: "%j, %D", css:daysStyle}
];
gantt.config.fit_tasks = true;
gantt.config.columns = [
{name: "name", label: "<div class='searchEl'>Task name <input id='filter' style='width: 120px;' type='text'"+"placeholder='Search tasks...'></div>", tree: true, width: 170, tree : true, resize: true },
{name: "start_date", label: "Start time", align: "center", width: 150 , resize: true, editor: dateEditor},
{name: "duration", label: "Duration", align: "center", width: 50, editor: durationEditor},
{name: "user", label: "User", align: "center", width: 100},
{name: "state", label: "State", align: "center", width: 100, editor: stateEditor}
];
gantt.config.lightbox.sections = [
{name: "name", label: "Name", height:30, map_to:"name", type:"textarea", focus:true},
{name:"state", height:22, map_to:"state", type:"select", options: stateEditor.options},
{name:"template", height:37, type:"template", map_to:"my_template"},
{name: "time", height:72, map_to:"auto", type:"duration"}
];
gantt.config.lightbox.project_sections = [
{name: "name", label: "Name", height:30, map_to:"name", type:"textarea", focus:true},
{name: "time", height:72, map_to:"auto", type:"duration"}
];
gantt.locale.labels.section_name = "Title";
gantt.locale.labels.section_state = "State";
gantt.locale.labels.section_template = "Details";
gantt.config.lightbox.project_sections.allow_root = false;
gantt.attachEvent("onBeforeLightbox", function(id) {
var task = gantt.getTask(id);
task.my_template = "<span id='lightbox_users'>Assign to: </span>"+ task.user
+"<br> <span id='lightbox_progress'>Progress: </span>"+ task.progress*100 +" %";
return true;
});
gantt.config.lightbox.allow_root = false;
gantt.templates.task_text = function(start, end, task) {
return "<b>Name:</b> " + task.name + (task.user ? ",<b> Assign to:</b> " + task.user : "");
};
gantt.templates.tooltip_text = function(start, end, task) {
// Personnalisez ici le texte du tooltip pour chaque tâche (hover)
return "<b>" + task.name + "</b><br/>"
+ "Start: " + gantt.templates.tooltip_date_format(start) + "<br/>"
+ "End: " + gantt.templates.tooltip_date_format(end) + "<br/>"
+ "Duration: " + task.duration + " days" + "<br/>"
+ (task.state ? "<br/>State: " + task.state : "")
+ (task.user ? "<br/>User: " + task.user : "");
};
gantt.templates.task_class = function(start, end, task){
var css = "";
switch(task.state){
case "Opened":
css = "opened";
break;
case "Closed":
css = "closed";
break;
case "InProgress":
css = "in-progress";
break;
case "Late":
css = "late";
break;
case "Unscheduled":
css = "unscheduled";
break;
default:
css = "";
}
return css;
};
gantt.config.columns_resizable = true;
gantt.config.columns_autoresize = true;
gantt.addMarker({
start_date: new Date(), //a Date object that sets the marker's date
css: "today", //a CSS class applied to the marker
text: "Now", //the marker title
title: dateToStr( new Date()) // the marker's tooltip
});
if (this.$props.tasks.data.length < 50) {
gantt.config.open_tree_initially = true; //if more than 50 tasks, tasks will be closed by default
}
gantt.init(this.$refs.ganttContainer);
gantt.parse(this.$props.tasks);
gantt.attachEvent("onDataRender", function () {
const filterEl = document.querySelector("#filter")
filterEl.addEventListener('input', function (e) {
filterValue = filterEl.value;
gantt.refreshData();
});
});
let filterValue = "";
function filterLogic(task, match) {
match = match || false;
// check children
gantt.eachTask(function (child) {
if (filterLogic(child)) {
match = true;
}
}, task.id);
// check task
if (task.name.toLowerCase().indexOf(filterValue.toLowerCase()) > -1) {
match = true;
}
return match;
}
gantt.attachEvent("onBeforeTaskDisplay", function (id, task) {
if (!filterValue) {
return true;
}
return filterLogic(task);
});
gantt.$root.appendChild(controlsDiv);
gantt.$root.appendChild(legend);
}
}
</script>
<style>