Перейти к основному содержимому

Связь данных и управление состоянием в Angular Gantt

Angular Gantt поддерживает две модели владения данными:

  1. Состояние Angular / хранение как источник истины (рекомендуется для большинства приложений).
  2. Gantt как источник истины (ориентировано на производительность для специализированных страниц).

Выбирайте одну модель на страницу/область функционала и соблюдайте её единообразно.

Состояние Angular или хранилище как источник истины

В этой модели:

  • состояние вашего компонента или RxJS‑хранилища владеют tasks и links,
  • обёртка получает массивы через входы,
  • изменения графика фиксируются через data.save или data.batchSave,
  • коллбэки обновляют ваше состояние/хранилище, и новые массивы возвращаются в <dhx-gantt>.

Лучшее применение

  • страницы Angular с панелями инструментов и формами, которые должны оставаться синхронизированными с графиком,
  • кодовые базы команд, уже построенные на сервисах и RxJS,
  • предсказуемые переходы состояния и упрощенная отладка.

Преимущества и недостатки

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

Антишаблоны, которых следует избегать

  • изменение данных через instance, при этом отправляя устаревшие массивы tasks/links из состояния Angular,
  • игнорирование data.save / data.batchSave и ожидание, что редактирования графика будут автоматически сохраняться в состоянии вашего приложения.

Полный пример потока (состояние компонента)

import { Component } from '@angular/core';
import {
DhxGanttComponent,
type AngularGanttDataConfig,
type SerializedTask,
type SerializedLink,
} from '@dhtmlx/trial-angular-gantt';

@Component({
standalone: true,
imports: [DhxGanttComponent],
template: `<dhx-gantt [tasks]="tasks" [links]="links" [data]="dataConfig"></dhx-gantt>`,
})
export class GanttPageComponent {
tasks: SerializedTask[] = [];
links: SerializedLink[] = [];

dataConfig: AngularGanttDataConfig = {
save: (entity, action, item, id) => {
if (entity === 'task') {
if (action === 'create') this.tasks = [...this.tasks, item];
if (action === 'update') this.tasks = this.tasks.map((t) => String(t.id) === String(id) ? { ...t, ...item } : t);
if (action === 'delete') this.tasks = this.tasks.filter((t) => String(t.id) !== String(id));
}

if (entity === 'link') {
if (action === 'create') this.links = [...this.links, item];
if (action === 'update') this.links = this.links.map((l) => String(l.id) === String(id) ? { ...l, ...item } : l);
if (action === 'delete') this.links = this.links.filter((l) => String(l.id) !== String(id));
}
},
};
}

Gantt как источник истины

В этой модели график и бэкэнд владеют большей частью жизненного цикла данных во время выполнения.

Лучшее применение

  • очень больших наборов данных,
  • экранов, ориентированных на график,
  • тяжелого автоматического планирования или цепочечных редактирований, где частые обновления в приложении дороги.

Преимущества и недостатки

  • менее очевидная видимость текущего состояния графика в сервисах/компонентах Angular,
  • требуется дополнительная дисциплина при смешивании редких обновлений входов с императивными операциями.

Антишаблоны, которых следует избегать

  • частичное зеркалирование без четкого плана согласования,
  • повторная подача устаревших снимков сервера после того, как пользователи уже изменили данные в графике.

Пример серверного транспорта

dataConfig = {
load: '/api/gantt/load',
save: async (entity: string, action: string, payload: any, id: string | number) => {
const response = await fetch(`/api/gantt/${entity}`, {
method: action === 'delete' ? 'DELETE' : 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action, payload, id }),
});

return await response.json();
},
};

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

Контракты обратного вызова

data.save

save передается в gantt.createDataProcessor(save) и получает данные изменений.

Типичная сигнатура функции:

(entity: string, action: string, data: any, id: string | number) => any

Используйте это, когда изменения в основном единичны и легко применяются по одному.

data.batchSave

batchSave получает сгруппированные данные изменений:

interface BatchChanges {
tasks?: DataCallbackChange[];
links?: DataCallbackChange[];
resources?: DataCallbackChange[];
resourceAssignments?: DataCallbackChange[];
}

Соответствие сущности к bucket включает:

  • task / tasks -> tasks
  • link / links -> links
  • resource / resources -> resources
  • assignment / resourceAssignment / resourceAssignments -> resourceAssignments

Краткое описание поведения очереди:

  • небольшая пакетная обработка с дребезгом (debounce),
  • create + update объединены в один create с последними данными,
  • create + delete удалены,
  • внутренний !nativeeditor_status удаляется из полезных нагрузок.

Используйте это, когда одно действие графика может инициировать множество последующих изменений.

Загрузка данных в состояние Angular

Локальное состояние компонента

Используйте локальные поля компонента для небольших страниц или прототипов.

Загружайте данные в Angular, затем присваивайте массивы входам tasks и links. Обработчики обратного вызова держите в том же компоненте.

RxJS‑сервисы / хранилища (рекомендуется для приложений среднего и крупного размера)

Используйте внедряемый сервис с BehaviorSubject (или аналогом) для хранения задач, ссылок и состояния UI.

Это паттерн, используемый в открытом примере Angular и документированный в Using Angular Gantt with RxJS.

Загрузка из API в состояние Angular

Типичный поток:

  1. Получайте данные в сервисе или разрешителе маршрута.
  2. Нормализуйте или сопоставляйте форматы дат при необходимости.
  3. Поместите данные в ваше хранилище/состояние компонента.
  4. Передайте массивы в <dhx-gantt>.
  5. Обрабатывайте редактирования с data.save или data.batchSave и сохраняйте в backend.

Используйте это, когда состояние Angular является источником истины, а бэкенд по-прежнему служит долгосрочным источником данных.

Gantt как источник истины в приложении Angular

Когда эта модель имеет смысл

Выберите это, когда страница в основном состоит из графика и окружающий UI Angular не требует реагировать на каждое обновление задачи/ссылки.

Предоставление исходных данных

Вы можете инициализировать данные, управляемые Gantt, любым из следующих шаблонов:

  • data.load URL
  • data.load функция (синхронная или асинхронная)
  • начальные массивы tasks/links, затем перестаньте рассматривать их как живые входы источника истины

Как работают обновления

Экземпляр Gantt применяет изменения пользователя локально и отправляет их через save или batchSave.

Angular не нужно переназначать tasks/links после каждого изменения, если вы явно не хотите их зеркально отражать.

Перепривязка ID и ответственность бэкенда

Создание действий часто начинается с временных клиентских ID.

  • В режиме save ответы бэкенда должны возвращать постоянные IDs, чтобы Gantt мог выполнить переназначение внутренних записей.
  • В режиме batchSave нет пути возврата на уровне элементов, поэтому переназначение ID должно обрабатываться явно в вашем процессе сохранения, если бэкенд присваивает новые IDs.

Бэкенд остается ответственным за:

  • валидацию,
  • проверки разрешений,
  • постоянное присвоение ID,
  • согласованные полезные нагрузки ответов.

Продолжение

Need help?
Got a question about the documentation? Reach out to our technical support team for help and guidance. For custom component solutions, visit the Services page.