dhtmlxGantt使用教程:网格中的内联编辑

翻译|使用教程|编辑:杨鹏连|2021-03-30 13:14:00.447|阅读 57 次

概述:内联编辑使您可以直接在网格中进行任何更改:创建和更新任务,设置任务之间的连接,定义开始和结束日期或修改持续时间-所有这些都通过内置编辑器进行。

# 31款JAVA开发必备控件和工具 # 企业数字化建设合规无风险[专题]

相关链接:

dhtmlxGantt是用于跨浏览器和跨平台应用程序的功能齐全的Gantt图表。可满足项目管理应用程序的所有需求,是最完善的甘特图图表库。它允许你创建动态甘特图,并以一个方便的图形化方式可视化项目进度。有了dhtmlxGantt,你可以显示活动之间的依赖关系,显示具有完成百分比阴影的当前任务状态以及组织活动到树结构。

点击下载dhtmlxGantt试用版

dhtmlxGantt提供了两个用于编辑内容的选项:

  • 在Lightbox编辑表单的帮助下
  • 通过使用“网格”区域中的内联编辑器
内联编辑使您可以直接在网格中进行任何更改:创建和更新任务,设置任务之间的连接,定义开始和结束日期或修改持续时间-所有这些都通过内置编辑器进行。

内联网格编辑

要启用内联编辑,您需要:

  • 指定编辑器配置列表,并使用编辑器对象的map_to属性将必要的编辑器映射到网格列
var textEditor = {type: "text", map_to: "text"};
var dateEditor = {type: "date", map_to: "start_date", min: new Date(2018, 0, 1), 
    max: new Date(2019, 0, 1)};
var durationEditor = {type: "number", map_to: "duration", min:0, max: 100};
  • 在列配置中,使用editor属性来定义应在列中使用的编辑器
gantt.config.columns = [
    {name: "text", tree: true, width: '*', resize: true, editor: textEditor},
    {name: "start_date", align: "center", resize: true, editor: dateEditor},
    {name: "duration", align: "center", editor: durationEditor},
    {name: "add", width: 44}
];
您可以看一下视频指南,该指南显示了如何在网格中实现内联编辑。

编辑类型

内联编辑器存储在editor_types配置对象中。

有几种预定义的内联编辑器:

  • 文本编辑器-用于编辑文本列,例如任务名称
  • 数字编辑器-用于编辑数字列,例如任务持续时间,订单等。
  • 日期编辑器-用于编辑日期列,例如任务的开始和结束日期
  • 选择编辑器-用于从列表中选择一个选项
  • 前任编辑器-用于为当前编辑的任务设置任务前任。该编辑器获取任务的WBS代码以设置与先前任务的连接。
var editors = {
    text: {type: "text", map_to: "text"},
    start_date: {type: "date", map_to: "start_date", min: new Date(2018, 0, 1), 
        max: new Date(2019, 0, 1)},
    end_date: {type: "date", map_to: "end_date", min: new Date(2018, 0, 1), 
        max: new Date(2019, 0, 1)},
    duration: {type: "number", map_to: "duration", min:0, max: 100},
    priority: {type:"select", map_to:"priority", options:gantt.serverList("priority")},
    predecessors: {type: "predecessor", map_to: "auto"}
};
日期编辑器中的日期限制

从v6.3开始,日期内联编辑器的最小和最大输入值没有默认限制。

如果希望时间刻度上显示的日期限制日期内联编辑器的最小值和最大值(除非提供了自定义的最小值/最大值),则可以指定动态最小值/最大值:

const dateEditor = {type: "date", map_to: "start_date", 
    min: function(taskId){
      return gantt.getState().min_date
    },
    max: function( taskId ){
      return gantt.getState().max_date
    }
};
结束日期的编辑器

如果将格式用于任务的包含结束日期,并希望通过网格中的内联编辑使其正确运行,则必须创建一个特殊的编辑器来编辑任务的包含结束日期,如下所示:

// inclusive editor for end dates
// use the default editor, but override the set_value/get_value methods
var dateEditor = gantt.config.editor_types.date;
gantt.config.editor_types.end_date = gantt.mixin({
   set_value: function(value, id, column, node){
        var correctedValue = gantt.date.add(value, -1, "day");
        return dateEditor.set_value.apply(this, [correctedValue, id, column, node]);
   },
   get_value: function(id, column, node) {
        var selectedValue = dateEditor.get_value.apply(this, [id, column, node]);
        return gantt.date.add(selectedValue, 1, "day");
   },
}, dateEditor);
 
var textEditor = {type: "text", map_to: "text"};
var startDateEditor = {type: "date", map_to: "start_date"};
var endDateEditor = {type: "end_date", map_to: "end_date"};
var durationEditor = {type: "number", map_to: "duration", min:0, max: 100};
 
gantt.config.columns = [
    {name: "text", label: "Name", tree: true, width: 200, editor: textEditor, 
        resize: true},
    {name: "duration", label: "Duration", width:80, align: "center", 
        editor: durationEditor, resize: true},
    {name: "start_date", label: "Start", width:140, align: "center", 
        editor: startDateEditor, resize: true},
    {name: "end_date", label: "Finish", width:140, align: "center", 
        editor: endDateEditor, resize: true}
];
 
// change lightbox and grid templates to display dates of tasks in an inclusive format
gantt.templates.task_end_date = function(date){
    return gantt.templates.task_date(new Date(date.valueOf() - 1)); 
};
 
 
var gridDateToStr = gantt.date.date_to_str("%Y-%m-%d");
gantt.templates.grid_date_format = function(date, column){
    if(column === "end_date"){
        return gridDateToStr(new Date(date.valueOf() - 1)); 
    }else{
        return gridDateToStr(date); 
    }
}
格式化前置编辑器的值

从v6.3开始,Gantt允许直接从内联编辑器中指定链接的类型以及滞后/超前值。

为此,您需要使用链接格式化程序模块,并将LinksFormatter的一个实例提供到先前的编辑器中:

var formatter = gantt.ext.formatters.durationFormatter({
    enter: "day", 
    store: "day", 
    format: "auto"
});
var linksFormatter = gantt.ext.formatters.linkFormatter({durationFormatter: formatter});
 
var editors = {
    text: {type: "text", map_to: "text"},
    start_date: {type: "date", map_to: "start_date", 
                min: new Date(2018, 0, 1), max: new Date(2019, 0, 1)},
    end_date: {type: "date", map_to: "end_date", 
                min: new Date(2018, 0, 1), max: new Date(2019, 0, 1)},
    duration: {type: "duration", map_to: "duration", 
                min:0, max: 100, formatter: formatter},
    priority: {type: "select", map_to: "priority", 
                options:gantt.serverList("priority")},
    predecessors: {type: "predecessor", map_to: "auto", formatter: linksFormatter} 
};
 
gantt.config.columns = [
    {name: "wbs", label: "#", width: 60, align: "center", template: gantt.getWBSCode},
    {name: "text", label: "Name", tree: true, width: 200, editor: editors.text, 
        resize: true},
    {name: "start_date", label: "Start", width:80, align: "center", 
      editor: editors.start_date, resize: true},
    {name: "predecessors", label: "Predecessors",width:80, align: "left", 
      editor: editors.predecessors, resize: true, template: function(task){
            var links = task.$target;
            var labels = [];
            for(var i = 0; i < links.length; i++){
                var link = gantt.getLink(links[i]);
                labels.push(linksFormatter.format(link)); 
            }
            return labels.join(", ")
        }},
    {name:"add"}
];
自定义内联编辑器

您还可以指定自定义内联编辑器。为此,您需要通过以下方式创建一个新的编辑器对象:

gantt.config.editor_types.custom_editor = {
  show: function (id, column, config, placeholder) {
    // called when input is displayed, put html markup of the editor into placeholder 
    // and initialize your editor if needed:
    var html = "<div><input type='text' name='" + column.name + "'></div>";
    placeholder.innerHTML = html;
  },
  hide: function () {
    // called when input is hidden 
    // destroy any complex editors or detach event listeners from here
  },
 
  set_value: function (value, id, column, node) {
    // set input value
  },
 
  get_value: function (id, column, node) {
    // return input value
  },
 
  is_changed: function (value, id, column, node) {
    //called before save/close. Return true if new value differs from the original one
    //returning true will trigger saving changes, returning false will skip saving 
  },
 
  is_valid: function (value, id, column, node) {
    // validate, changes will be discarded if the method returns false
    return true/false;
  },
 
  save: function (id, column, node) {
     // only for inputs with map_to:auto. complex save behavior goes here
  },
  focus: function (node) {
  }
}
为了实现可重用的编辑器,需要记住一些关键点:
  • 通常,get_value不修改任务对象。该方法仅返回内联编辑器的当前值。如果该值被认为是有效的,甘特将使用该值自动更新相关任务。
  • 使用map_to编辑器的配置选项可以指定任务的哪个属性应由编辑器更新,但不要将其硬编码到编辑器中。通过这种方式,您可以将编辑器重用于不同的列。
  • 除非您使用复杂的javascript小部件,否则无需在hide函数中指定任何逻辑,因此可以将其保留为空。否则,使用此方法调用析构函数或清理显示编辑器时附加的任何事件处理程序。
  • 确保实现is_changed和is_valid功能:
  • 如果is_changed始终返回true,则每次关闭编辑器时,编辑器都会触发更新(可以发送到后端)。仅当输入值与初始状态相比实际发生更改时,此方法才应返回true;否则,该方法应返回true。
  • is_valid 用于防止输入无效值。
  • 如果您要实现的编辑器比将值写入任务的属性要复杂的多(例如内置的前身编辑器就是一个很好的例子),则需要在save函数中实现所需的逻辑并指定map_to选项输入到“ auto”。在这种情况下,甘特图不会修改任务对象,而是save在需要将所做的更改应用于编辑器时调用该函数。
这是一个简单数字输入的实现示例。请注意,该hide方法可以是空函数,并且save可以完全跳过该方法。
var getInput = function(node){
    return node.querySelector("input");
};
 
gantt.config.editor_types.simpleNumber = {
    show: function (id, column, config, placeholder) {
        var min = config.min || 0,
        max = config.max || 100;
 
        var html = "<div><input type='number' min='" + min + 
                      "' max='" + max + "' name='" + column.name + "'></div>";
        placeholder.innerHTML = html;
    },
    hide: function () {
      // can be empty since we don't have anything to clean up after the editor 
          // is detached
    },
    set_value: function (value, id, column, node) {
        getInput(node).value = value;
    },
    get_value: function (id, column, node) {
        return getInput(node).value || 0;
    },
    is_changed: function (value, id, column, node) {
        var currentValue = this.get_value(id, column, node);
        return Number(value) !== Number(currentValue);
    },
    is_valid: function (value, id, column, node) {
        return !isNaN(parseInt(value, 10));
    },
    focus: function (node) {
        var input = getInput(node);
        if (!input) {
            return;
        }
        if (input.focus) {
            input.focus();
        }
 
        if (input.select) {
          input.select();
        }
    }
};
之后,您可以使用与内置编辑器相同的方式来使用编辑器:
var numberEditor = {type: "simpleNumber", map_to: "quantity", min:0, max: 50}; 
 
gantt.config.columns = [
    ...
    {name: "quantity", label: "Quantity", width: 80, editor: numberEditor, 
        resize: true},
    ...
];
请注意,hide在这种情况下,我们不需要实现该方法,因为甘特图会自动分离编辑器的DOM元素,并且在关闭编辑器后无需清理其他内容。

编辑器

hide如果您在内联编辑器中使用复杂的小部件,则可能需要添加逻辑。

例如,让我们考虑以下使用jQuery的DatePicker输入的实现。在这种情况下,我们需要在将日期选择器小部件与DOM分离后销毁它。

先决条件:

<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
编辑:
gantt.config.editor_types.custom_datepicker_editor = {
    show: function (id, column, config, placeholder) {
        placeholder.innerHTML = "<div><input type='text' id='datepicker' name='" + 
                                  column.name + "'></div>";
        $("#datepicker").datepicker({
            dateFormat: "yy-mm-dd",
            onSelect: function(dateStr){
                gantt.ext.inlineEditors.save()
            }
        });
    },
    hide: function (node) {
        $("#datepicker").datepicker( "destroy" );
    },
 
    set_value: function (value, id, column, node) {
        $("#datepicker").datepicker("setDate", value);
    },
 
    get_value: function (id, column, node) {
        return $("#datepicker").datepicker( "getDate" );
    },
 
    is_changed: function (value, id, column, node) {
        return (+$("#datepicker").datepicker( "getDate" ) !== +value);
    },
    is_valid: function (value, id, column, node) {
        return !(isNaN(+$("#datepicker").datepicker( "getDate" )))
    },
    save: function (id, column, node) {
    },
    focus: function (node) {
    }
};
 
let dateEditor = {
    type: "custom_datepicker_editor",
    map_to: "start_date"
};
 
gantt.config.columns = [
    {name: "text", tree: true, width: '*', resize: true},
    {name: "start_date", align: "center", resize: true, editor: dateEditor},
    {name: "duration", align: "center"},
    {name: "add", width: 44}
];
editor.save

save仅当您的编辑器需要一次修改任务的多个属性,或者希望它修改不同于任务的对象时,才需要使用该功能。

在这种情况下,您可以保留适当的实现以get_value进行内置验证,但是gantt本身不会尝试将编辑器的值应用于任务,save而是将调用该函数。

之后save被调用时,你需要解释的输入值,并应用变为带有自定义代码甘特。方法完成后,Gantt将调用onSave事件save,但不会为修改后的行调用gantt.updateTask。

笔记!save仅当您map_to:"auto"在编辑器的配置中指定时,才会调用该方法:

var editors = {
    ...
    predecessors: {type: "predecessor", map_to: "auto"}
};
内置的前身编辑器就是此类控件的一个很好的例子。您可以在相关示例中找到其简化的实现。

关产品推荐:

VARCHART XGantt支持ActiveX、.Net等平台的C#甘特图控件

AnyGantt构建复杂且内容丰富的甘特图的理想工具

jQuery Gantt Package基于HTML5 / jQuery的跨平台jQuery Gantt包

phGantt Time Package对任务和时间的分配管理的甘特图

APS帮助提升企业生产效率,真正实现生产排程可视化呈现与控制,快速有效响应不同场景的生产计划,提高准时交货能力,提高产能和资源利用率

想要购买dhtmlxGantt正版授权,或了解慧都APS系统请点击【咨询在线客服】

标签:

本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至hey@evget.com

文章转载自:DHTMLX

为你推荐

  • 推荐视频
  • 推荐活动
  • 推荐产品
  • 推荐文章
  • 慧都慧问
在线咨询
联系我们
TOP
在线客服系统
live chat