dhtmlxGantt с Angular

Для работы с этой документацией полезно иметь базовое понимание концепций и паттернов Angular. Если вы новичок в Angular, ознакомьтесь с документацией Angular для быстрого старта.

DHTMLX Gantt хорошо интегрируется с Angular. Мы подготовили несколько примеров, чтобы показать, как использовать DHTMLX Gantt в проектах Angular. Вы можете изучить эти примеры онлайн через Replit или ознакомиться с демо на GitHub.

Настройка проекта

Прежде чем начать, убедитесь, что у вас установлены Angular CLI и Node.js.

Чтобы создать новый проект Angular, выполните:

ng new my-angular-gantt-app

Эта команда установит все необходимые инструменты и зависимости, так что дополнительная настройка не требуется.

Установка зависимостей

Перейдите в директорию вашего проекта:

cd my-angular-gantt-app

Запустите приложение, используя одну из следующих команд:

yarn start

или

npm start

Теперь приложение будет доступно по адресу http://localhost:4200.

Gantt Angular app running

Добавление Gantt в приложение

Чтобы включить DHTMLX Gantt в ваше приложение, сначала остановите запущенное приложение, нажав Ctrl+C в терминале. Затем выполните следующие шаги.

Шаг 1: Установка пакета

Профессиональные версии библиотеки доступны через npm/yarn из нашего частного репозитория. Ознакомьтесь с этим руководством для доступа.

После получения пробной версии Gantt установите её с помощью:

  • Для npm:
npm install @dhx/trial-gantt
  • Для yarn:
yarn add @dhx/trial-gantt

В качестве альтернативы, если у вас есть zip-пакет библиотеки, вы можете установить его локально.

Шаг 2: Создание компонента Gantt

Создайте новую папку с именем gantt в каталоге src/app/. Внутри этой папки создайте два файла: gantt.component.ts и gantt.component.css.

Импорт исходных файлов

В gantt.component.ts импортируйте необходимые исходные файлы Gantt. В зависимости от метода установки пути импорта будут различаться:

  • Если вы установили Gantt из локальной папки:
import { Gantt } from 'dhtmlx-gantt';
@import "@dhtmlx-gantt/codebase/dhtmlxgantt.css";
  • Если вы установили пробную версию:
import { Gantt } from '@dhx/trial-gantt';
@import "@dhx/trial-gantt/codebase/dhtmlxgantt.css";

В этом примере мы будем использовать пробную версию.

Теперь, в gantt.component.ts, включите следующий код для настройки шаблона Gantt:

import { Component, ElementRef, OnInit, 
    ViewChild, ViewEncapsulation } from '@angular/core';
import { Gantt, GanttStatic } from "@dhx/trial-gantt";
 
@Component({
    encapsulation: ViewEncapsulation.None,
    selector: 'gantt',
    styleUrls: ['./gantt.component.css'],
    template: `<div #gantt_here class='gantt-chart'></div>`,
})
export class GanttComponent implements OnInit {
    @ViewChild('gantt_here', { static: true }) ganttContainer!: ElementRef;
    private _gantt?: GanttStatic;
 
    ngOnInit() {
        let gantt = Gantt.getGanttInstance();
        gantt.init(this.ganttContainer.nativeElement);
 
        this._gantt = gantt;
    }
    ngOnDestroy() {
        if (this._gantt) this._gantt.destructor();
    }
}

Этот код использует метод Angular ngOnInit() для инициализации экземпляра Gantt и метод ngOnDestroy() для очистки компонента, когда он больше не используется.

Для стилей в gantt.component.css вы можете добавить следующее:

@import "@dhx/trial-gantt/codebase/dhtmlxgantt.css";
.gantt-chart {
    position: relative;
    width: 100%;
    height: 600px;
}

Шаг 3: Интеграция Gantt в приложение

Чтобы включить компонент Gantt в ваше приложение, обновите src/app/app.component.ts следующим содержанием:

import { Component } from '@angular/core';
 
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'DHTMLX Gantt with Angular';
}

Далее, в src/app/app.module.ts, зарегистрируйте GanttComponent следующим образом:

import { NgModule } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";
 
import { AppComponent } from "./app.component";
import { GanttComponent } from './gantt/gantt.component';
 
@NgModule({
  declarations: [AppComponent, GanttComponent],
  imports: [BrowserModule],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}

В src/app/app.component.html замените содержимое по умолчанию на:

<gantt></gantt>

Наконец, в src/main.ts обновите код следующим образом:

import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";
import { AppModule } from "./app/app.module";
 
platformBrowserDynamic()
  .bootstrapModule(AppModule)
  .catch((err) => console.error(err));

После внесения всех изменений снова запустите приложение. Вы должны увидеть пустую диаграмму Gantt, отображаемую на странице.

Gantt Angular init

Шаг 4. Предоставление данных

Чтобы загрузить данные в Angular Gantt, вам нужно будет настроить службы задач и связей. Но сначала давайте определим модели задач и связей.

Чтобы создать эти модели, выполните следующие команды:

ng generate class models/task --skip-tests
ng generate class models/link --skip-tests

Вновь созданный файл task.ts, расположенный в папке models, включите следующий код:

models/task.ts

export class Task {
    id!: number;
    start_date!: string;
    text!: string;
    progress!: number;
    duration!: number;
    parent!: number;
}

Аналогично, в файле link.ts в папке models добавьте этот код:

models/link.ts

export class Link {
    id!: number;
    source!: number;
    target!: number;
    type!: string;
}

Далее вы создадите службы задач и связей. Эти службы отвечают за генерацию задач или связей. Службы Angular используют внедрение зависимости, позволяя им предоставлять данные, функции или другие возможности приложению. Вам потребуется служба данных для предоставления задач и связей в Gantt.

Чтобы создать эти службы, выполните следующие команды:

ng generate service services/task --flat --skip-tests
ng generate service services/link --flat --skip-tests

В вновь созданном файле task.service.ts в папке services добавьте этот код:

services/task.service.ts

import { Injectable } from '@angular/core';
import { Task } from '../models/task';
 
@Injectable()
export class TaskService {
    get(): Promise<Task[]> {
        return Promise.resolve([
            { id: 1, text: 'Task #1', start_date: '2023-04-15 00:00', 
                duration: 3, progress: 0.6, parent: 0 },
            { id: 2, text: 'Task #2', start_date: '2023-04-18 00:00', 
                duration: 3, progress: 0.4, parent: 0 }
        ]);
    }
}

Для файла link.service.ts в той же папке services включите следующее:

services/link.service.ts

import { Injectable } from '@angular/core';
import { Link } from '../models/link';
 
@Injectable()
export class LinkService {
    get(): Promise<Link[]> {
        return Promise.resolve([
            { id: 1, source: 1, target: 2, type: '0' }
        ]);
    }
}

Декоратор @Injectable() используется здесь, чтобы сделать службу доступной для внедрения зависимости. Позже эти службы будут внедрены в компонент Gantt.

На данный момент метод get() предоставляет жестко закодированные данные через разрешенный промис. Однако вы можете изменить его, чтобы получать данные с сервера и возвращать промис. Компонент Gantt будет использовать TaskService и LinkService для получения задач и связей.

Чтобы это обеспечить, начните с импорта необходимых модулей в gantt.component.ts:

gantt.component.ts

import { TaskService } from "../services/task.service";
import { LinkService } from "../services/link.service";

Затем включите TaskService и LinkService в качестве провайдеров в декораторе @Component:

gantt.component.ts

@Component({
    encapsulation: ViewEncapsulation.None,
    selector: 'gantt',
    styleUrls: ['./gantt.component.css'],
    providers: [TaskService, LinkService],
    template: `<div #gantt_here class='gantt-chart'></div>`,
})

Это гарантирует создание нового экземпляра служб каждый раз, когда инициализируется GanttComponent. Чтобы подготовить службы к внедрению, добавьте следующий конструктор в класс GanttComponent:

gantt.component.ts

constructor(private taskService: TaskService, private linkService: LinkService) { }

Обновите функцию ngOnInit() следующим образом:

  • Установите формат данных для загрузки задач (в этом примере XML).
  • Вызовите службы для получения данных и дождитесь ответа перед их загрузкой в Gantt.

gantt.component.ts

let gantt = Gantt.getGanttInstance();
gantt.config.date_format = '%Y-%m-%d %H:%i';
gantt.init(this.ganttContainer.nativeElement);
 
Promise.all([this.taskService.get(), this.linkService.get()])
    .then(([data, links]) => {
        gantt.parse({ data, links });
    });
this._gantt = gantt;

Вот полный код для gantt.component.ts:

gantt.component.ts

import { Component, ElementRef, OnInit, 
    ViewChild, ViewEncapsulation } from '@angular/core';
import { TaskService } from '../services/task.service';
import { LinkService } from '../services/link.service';
import { Gantt, GanttStatic } from "@dhx/trial-gantt";
 
@Component({
    encapsulation: ViewEncapsulation.None,
    selector: 'gantt',
    styleUrls: ['./gantt.component.css'],
    providers: [TaskService, LinkService],
    template: `<div #gantt_here class='gantt-chart'></div>`,
})
export class GanttComponent implements OnInit {
    @ViewChild('gantt_here', { static: true }) ganttContainer!: ElementRef;
    private _gantt?: GanttStatic;
    constructor(private taskService: TaskService, private linkService: LinkService) { }
 
    ngOnInit() {
        let gantt = Gantt.getGanttInstance();
        gantt.config.date_format = '%Y-%m-%d %H:%i';
        gantt.init(this.ganttContainer.nativeElement);
        Promise.all([this.taskService.get(), this.linkService.get()])
            .then(([data, links]) => {
                gantt.parse({ data, links });
            });
        this._gantt = gantt;
    }
    ngOnDestroy() {
        if (this._gantt) this._gantt.destructor();
    }
}

После завершения этого, если вы перезагрузите страницу приложения, вы должны увидеть диаграмму Gantt, заполненную задачами:

Gantt Angular events

Шаг 5. Сохранение данных

Чтобы обрабатывать изменения, внесенные в Gantt, вы можете использовать обработчик dataProcessor. Этот инструмент позволяет взаимодействовать с серверной частью. Он может быть настроен как функция или объект маршрутизатора. С dhtmlxGantt обработчик поддерживает ответы Promise, обеспечивая корректную обработку завершенных действий.

Вот как вы можете создать DataProcessor с использованием метода API createDataProcessor() для захвата изменений:

gantt.createDataProcessor(function(entity, action, data, id) {
    gantt.message(`${entity} ${action}`);
});

Если ваша служба изменяет идентификатор задачи после создания новой записи (распространенная практика), убедитесь, что Promise возвращает объект вида {id: databaseId} или {tid: databaseId}. Это позволяет Gantt обновить запись с новым идентификатором базы данных. Для получения более подробной информации о серверной интеграции обратитесь к документации по серверной части.

Теперь ваша настройка Angular Gantt завершена! Вы можете ознакомиться с полным демо на GitHub.

Атаки XSS, CSRF и SQL-инъекции

Имейте в виду, что Gantt не включает встроенные механизмы защиты от угроз, таких как SQL-инъекции, XSS или CSRF-атаки. Обеспечение безопасности приложения является ответственностью разработчиков серверной части.

Для получения рекомендаций по обеспечению безопасности вашего приложения ознакомьтесь со статьей Безопасность приложения, в которой описаны общие уязвимости и способы их устранения.

К началу