Inline-Bearbeitung im Raster

Die dhtmlxGantt-Bibliothek bietet zwei Hauptmethoden zur Bearbeitung von Inhalten:

  • Über das Lightbox Bearbeitungsformular
  • Durch die Verwendung von Inline-Editoren direkt im Rasterbereich

Die Inline-Bearbeitung ermöglicht es Ihnen, Änderungen direkt im Raster vorzunehmen. Sie können Aufgaben erstellen und aktualisieren, Verbindungen herstellen, Start- und Enddaten festlegen oder Dauern mit integrierten Editoren anpassen.

Inline-Rasterbearbeitung

Um die Inline-Bearbeitung zu aktivieren, müssen Sie:

  • Eine Liste von Editor-Konfigurationen definieren und die map_to-Eigenschaft verwenden, um einen Editor mit einer bestimmten Rasterspalte zu verknüpfen.
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};
  • Die editor-Eigenschaft in der Spaltenkonfiguration verwenden, um den gewünschten Editor einer Spalte zuzuweisen.
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}
];

Related sample:  Inline editing

Weitere Details zur inlineEditors Objekt-API finden Sie im Artikel Inline-Editor-Erweiterung.

Für eine praktische Demonstration sehen Sie sich den Video-Leitfaden zur Implementierung der Inline-Bearbeitung im Raster an.

Arten von Editoren

Inline-Editoren sind im editor_types Konfigurationsobjekt definiert. Die Bibliothek bietet mehrere vorkonfigurierte Editoren:

  • text Editor: Wird für Textspalten verwendet, wie z.B. Aufgabennamen.
  • number Editor: Handhabt numerische Spalten, wie z.B. Aufgabendauer oder Reihenfolge.
  • duration Editor: Entwickelt für Dauerspalten. Er funktioniert, wenn die map_to: "duration"-Eigenschaft gesetzt ist und der Editor-Typ "duration" ist.
{ type: "duration", map_to: "duration", formatter: formatter }

Dieser Editor ist nützlich, wenn Sie Dauern angeben müssen, die sowohl einen numerischen Wert als auch eine Dauereinheit enthalten, wie 5 Tage. Er verwendet standardmäßig den Duration Formatter, aber Sie können seine Einstellungen ändern oder einen benutzerdefinierten Formatter verwenden.

  • date Editor: Wird für Datumsspalten wie Start- und Enddaten von Aufgaben verwendet.
  • select Editor: Ermöglicht die Auswahl einer Option aus einer vordefinierten Liste.
  • predecessor Editor: Ermöglicht das Festlegen von Vorgänger-Verbindungen für Aufgaben. Er verwendet WBS-Codes, um Verbindungen herzustellen.
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"}
};

Datumsgrenzen im Datums-Editor

Ab Version 6.3 gibt es keine Standardgrenzen mehr für die minimalen und maximalen Eingabewerte in date Inline-Editoren. Wenn Sie möchten, dass die sichtbaren Daten auf der Zeitskala den Eingabebereich begrenzen, können Sie dynamische min/max Werte festlegen:

const dateEditor = {type: "date", map_to: "start_date", 
    min: function(taskId){
      return gantt.getState().min_date
    },
    max: function(taskId){
      return gantt.getState().max_date
    }
};

Editor für inklusive Enddaten

Für Aufgaben, die das inklusive Enddatumsformat verwenden, können Sie einen spezifischen Editor erstellen, um dieses Format korrekt zu handhaben:

// inklusiver Editor für Enddaten
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: "Dauer", 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: "Ende", width:140, align: "center", 
        editor: endDateEditor, resize: true}
];
 
// Vorlagen anpassen, um Daten im inklusiven Format anzuzeigen
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); 
    }
}

Related sample:  Inklusiver Enddatum-Editor

Für weitere Details, sehen Sie sich den Artikel Task end date display & Inclusive end dates an.

Formatierung von Vorgänger-Editor-Werten

Diese Funktion ist nur in der PRO-Edition verfügbar.

Seit Version 6.3 unterstützt Gantt die Spezifikation von Verbindungstypen und Verzögerungs-/Vorlaufwerten direkt über den Inline-Editor. Um dies zu aktivieren, verwenden Sie das Link Formatter Modul und übergeben Sie eine LinksFormatter Instanz an den predecessor Editor:

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: "Vorgänger",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"}
];

Related sample:  Inline editing - keyboard navigation mode

Benutzerdefinierter Inline-Editor

Bei Bedarf können Sie einen benutzerdefinierten Inline-Editor erstellen. Beginnen Sie mit der Definition eines neuen Editor-Objekts:

gantt.config.editor_types.custom_editor = {
  show: function (id, column, config, placeholder) {
    var html = "<div><input type='text' name='" + column.name + "'></div>";
    placeholder.innerHTML = html;
  },
  hide: function () {},
  set_value: function (value, id, column, node) {},
  get_value: function (id, column, node) {},
  is_changed: function (value, id, column, node) {},
  is_valid: function (value, id, column, node) { return true; },
  save: function (id, column, node) {},
  focus: function (node) {}
}

Diese Struktur ermöglicht es Ihnen zu definieren, wie der Editor angezeigt, verborgen wird oder wenn Werte gesetzt, validiert oder gespeichert werden.

editor.save

Die save Funktion ist hilfreich, wenn Sie mehrere Eigenschaften einer Aufgabe gleichzeitig aktualisieren oder Objekte ändern möchten, die keine Aufgaben sind. In solchen Fällen können Sie weiterhin die get_value Funktion für integrierte Validierungszwecke verwenden, aber das Gantt-Diagramm selbst wird den Wert des Editors nicht auf die Aufgabe anwenden. Stattdessen wird die save Funktion aufgerufen.

Sobald save ausgelöst wird, müssen Sie die Eingabewerte bearbeiten und die notwendigen Änderungen am Gantt-Diagramm mit benutzerdefiniertem Code vornehmen. Nach Abschluss der save Funktion wird das onSave Ereignis ausgelöst. Das Gantt-Diagramm wird jedoch nicht automatisch gantt.updateTask für die aktualisierte Zeile aufrufen.

Wichtig: Die save Funktion wird nur ausgeführt, wenn Sie map_to:"auto" in der Editor-Konfiguration festgelegt haben:

var editors = {
    ...
    predecessors: {type: "predecessor", map_to: "auto"}
};

Ein gutes Beispiel dafür ist der eingebaute Vorgänger-Editor. Eine vereinfachte Version seiner Implementierung finden Sie im folgenden Beispiel:

Related sample:  Eingebauter Vorgänger-Editor

Inline-Bearbeitungsmodi

Grundlegende Inline-Bearbeitung

In diesem Modus können Sie Zellen durch Klicken mit der Maus bearbeiten und mit Hotkeys durch Zellen navigieren:

  • Tab: Fokus zum nächsten Editor verschieben
  • Shift+Tab: Fokus zurück zum vorherigen Editor verschieben

Related sample:  Inline editing

Tastaturnavigationsmodus

In diesem Modus können Sie die Tastatur sowohl zum Navigieren als auch zum Bearbeiten von Rasterzellen verwenden. Vordefinierte Tasten oder Tastenkombinationen helfen dabei:

  • Enter: Editor öffnen/schließen
  • Leertaste: Editor öffnen
  • Pfeiltasten: Durch Rasterzellen navigieren
  • Shift+Rechte Pfeiltaste: Eine Aufgabe einrücken, um sie zu verschachteln, und die übergeordnete Aufgabe in ein Projekt umwandeln
  • Shift+Linke Pfeiltaste: Ein Projekt wieder in eine einfache Aufgabe umwandeln
  • Shift+Oben Pfeiltaste: Einen Aufgabenast zusammenklappen
  • Shift+Unten Pfeiltaste: Einen Aufgabenast erweitern

Um die Tastaturnavigation zur Bearbeitung zu aktivieren, folgen Sie diesen Schritten:

  1. Aktivieren Sie das keyboard_navigation Plugin mit der Methode gantt.plugins:
gantt.plugins({
    keyboard_navigation: true
});
  1. Aktivieren Sie Tastaturnavigation und Zellnavigation:
gantt.config.keyboard_navigation = true;
gantt.config.keyboard_navigation_cells = true;

Sie können auch eine Platzhalterzeile aktivieren, die eine leere Zeile am Ende der Aufgabenliste ist, um neue Aufgaben hinzuzufügen:

gantt.config.placeholder_task = true;

Um automatisch den Fokus auf die Platzhalteraufgabe zu setzen, nachdem eine neue hinzugefügt wurde, verwenden Sie diese Konfiguration:

gantt.config.placeholder_task = {
    focusOnCreate: true
};

Zusätzlich können Sie die automatische Aufgabentyp-Erkennung aktivieren:

gantt.config.auto_types = true;

Related sample:  Inline editing - keyboard navigation mode

Benutzerdefinierte Inline-Bearbeitung

Sie können die Tastaturbelegung anpassen, um zu definieren, wie Editoren geöffnet werden, wie editorbezogene Ereignisse (wie Öffnen und Schließen) gehandhabt werden und wie die Bearbeitungslogik verwaltet wird. Dies geschieht durch Erstellen eines benutzerdefinierten Konfigurationsobjekts und Übergeben an eine bestimmte Methode:

var mapping = {
 init: function(inlineEditors){
  // InlineEditor Modulinitialisierung
  // Globale Listener für Bearbeitungsereignisse hinzufügen
 },
 
 onShow: function(inlineEditors, node){
  // Aktionen, die ausgeführt werden, wenn der Editor angezeigt wird
 },
 
 onHide: function(inlineEditors, node){
  // Bereinigungsaktionen, wenn der Editor verborgen wird
 }
};
 
gantt.ext.inlineEditors.setMapping(mapping);

Related sample:  Inline editing - Custom keyboard mapping

Benutzerdefinierte Zuordnung für Platzhalteraufgaben

Stellen Sie sich zwei Szenarien vor, während Sie die Tastaturnavigation, Inline-Editoren und eine Platzhalteraufgabe verwenden:

Szenario 1: Nachdem Sie einen Namen für eine neue Platzhalteraufgabe eingegeben und die Tabulatortaste gedrückt haben, erwarten Sie, dass die nächste Zelle der Aufgabe geöffnet wird. Stattdessen wird der Fokus auf die neue Platzhalteraufgabe darunter verschoben, ohne den Editor zu öffnen.

Szenario 2: Wenn Sie einen Namen für eine neue Platzhalteraufgabe eingeben und auf die nächste Zelle klicken, wird der Fokus auf die Platzhalteraufgabe statt auf die angeklickte Zelle gesetzt.

Sie können diese Probleme lösen, indem Sie benutzerdefinierte Logik für die Handhabung von Maus- und Tastaturinteraktionen mit dem Inline-Editor definieren. Hier ist ein Beispiel:

Related sample:  Gantt. Benutzerdefinierte Zuordnung für Platzhalteraufgabe

Validierung von Eingabewerten

Beim Bearbeiten einer Zelle im Raster können Fehler auftreten. Um das Speichern ungültiger Werte zu verhindern, sollten Sie Eingaben vor dem Schließen des Editors validieren. Dies kann auf zwei Arten erfolgen:

So verhält sich der Editor mit aktivierter Validierung:

  • Durch Drücken von Escape wird der Editor geschlossen, ohne Änderungen zu speichern.
  • Durch Drücken von Enter werden gültige Werte gespeichert und der Editor geschlossen; andernfalls wird der Wert verworfen.
  • Durch Drücken von Tab oder Klicken auf eine andere Zelle während der Bearbeitung werden gültige Werte gespeichert und der Fokus verschoben, während ungültige Werte zurückgesetzt und der Editor geschlossen werden.

Weitere Details zur clientseitigen oder serverseitigen Validierung finden Sie im Artikel Validierung.

Verhindern, dass der Editor geschlossen wird

Standardmäßig setzt Gantt ungültige Eingabewerte zurück und schließt den Editor, wenn die Validierung fehlschlägt. Um zu vermeiden, dass der Editor wiederholt geöffnet wird, können Sie ein Warnfeld verwenden, um Benutzern zu ermöglichen, falsche Werte zu korrigieren. Dies erfordert eine benutzerdefinierte Tastaturbelegung, wie im Folgenden gezeigt:

function editAnotherCell(inlineEditors){
  var value = inlineEditors.getValue();
  if(confirm(`does '${value}' look ok to you?`)){
    inlineEditors.save();
  }
}
 
var mapping = {
  init: function(inlineEditors){
    gantt.attachEvent("onTaskClick", function (id, e) {
      var cell = inlineEditors.locateCell(e.target);
      if (cell && inlineEditors.getEditorConfig(cell.columnName)) {
        if (inlineEditors.isVisible()) editAnotherCell(inlineEditors)
        else inlineEditors.startEdit(cell.id, cell.columnName);
        return false;
      }
      return true;
    });
    gantt.attachEvent("onEmptyClick", function () {
      inlineEditors.hide();
      return true;
    });
  },
 
  onShow: function(inlineEditors, node){
 
    node.onkeydown = function (e) {
      e = e || window.event;
      if(e.defaultPrevented){
        return;
      }
 
      var keyboard = gantt.constants.KEY_CODES;
 
      var shouldPrevent = true;
      switch (e.keyCode) {
        case gantt.keys.edit_save:
          var value = inlineEditors.getValue();
          if(confirm(`does '${value}' look ok to you?`)){
            inlineEditors.save();
          }
 
          break;
        case gantt.keys.edit_cancel:
          inlineEditors.hide();
          break;
        case keyboard.TAB:
          if(e.shiftKey){
            if (inlineEditors.isVisible()) editAnotherCell(inlineEditors)
            else inlineEditors.editPrevCell(true);
          }else{
            if (inlineEditors.isVisible()) editAnotherCell(inlineEditors)
            else inlineEditors.editNextCell(true);
          }
          break;
        default:
          shouldPrevent = false;
          break;
      }
 
      if(shouldPrevent){
        e.preventDefault();
      }
    };
  },
 
  onHide: function(inlineEditors, node){}
};
 
gantt.ext.inlineEditors.setMapping(mapping);
 
gantt.init("gantt_here");

Related sample:  Benutzerdefinierte Tastaturbelegung

Editor mit einem Klick öffnen

Im Einzelmodus öffnet ein Klick auf eine Aufgabe den Inline-Editor.

Im Mehrfachauswahlmodus wird beim Klicken auf eine nicht ausgewählte Aufgabe diese zuerst ausgewählt, und der Editor öffnet sich erst beim zweiten Klick. Um den Editor im Mehrfachauswahlmodus beim ersten Klick zu aktivieren, verwenden Sie die Konfiguration inline_editors_multiselect_open:

gantt.plugins({
  multiselect: true
});
 
...
 
gantt.config.inline_editors_multiselect_open = true;
Zurück nach oben