Integrating Gantt chart components into your Angular Web app with SCSS and custom configuration

DlhSoft
Gantt chart libraries
6 min readNov 22, 2023

Today, let’s see how one can add a GanttChartView instance — available with DlhSoft Gantt Chart Hyper Library — into a Web application developed using Angular framework.

And we’ll also configure it properly to display resources as images, and will set up other things as well.

Note that here we’ll skip the setup process for Angular framework itself. But, of course, you can follow the first part of our tutorial if you need to perform those steps too, yourself.

Now, assuming that we have the Angular app’s folder ready (and that you have npm installed on your computer), let’s see how we can add an instance of GanttChartView component.

To do that, open Terminal (now you can do that in Windows too, through PowerShell scripting!), navigate into the app folder and use this command to get the DlhSoft package:

npm install @dlhsoft/ganttcharthyperlibrary

Next, we need to select the files we need from the node module. Because we only need the GanttChartView component for this sample app, we only need to copy these two files (into a specific subfolder of our app, as indicated below):

mkdir src/app/DlhSoft
cp node_modules/@dlhSoft/ganttcharthyperlibrary/DlhSoft.ProjectData.GanttChart.HTML.Controls.js src/app/DlhSoft/
cp node_modules/@dlhSoft/ganttcharthyperlibrary/DlhSoft.ProjectData.GanttChart.HTML.Controls.d.ts src/app/DlhSoft/

Then, we need to reference the JavaScript file in our angular.json:

{
…,
"projects": {
"my-app": {
…,
"architect": {
"build": {
…,
"options": {

"scripts": ["src/app/DlhSoft/DlhSoft.ProjectData.GanttChart.HTML.Controls.js"]

"test": {
"build": {
…,
"options": {

"scripts": ["src/app/DlhSoft/DlhSoft.ProjectData.GanttChart.HTML.Controls.js"]

}

We’ll also configure TypeScript to use non-strict syntax to accept the GanttChartView definitions as they were originally designed, modifying tsconfig.json too:

{

"compilerOptions": {

"strict": false,
"strictPropertyInitialization": false,

}

}

Finally, time to go TypeScript. Let’s import the module we need first, in our app.module.ts, somewhere:


import { GanttChartView } from './DlhSoft/DlhSoft.ProjectData.GanttChart.Angular.Components';
@NgModule({
declarations: [
AppComponent,
GanttChartView
],

})

… and then we can easily inject the component somewhere into the UI page we want to display the Gantt Chart diagram:

<ganttchartview [items]="items" [settings]="settings" [license]="license"
[change]="onItemChanged" style="min-height: 388px; width: 100%;">

</ganttchartview>

As you can see from the Angular definition above, we’ll need to set up some things “behind the scenes”, e.g. in app.component.ts, of course:

  • an items array to hold the data for the bars (and dependencies between them) to be displayed; hierarchically, if needed, using indentation field values, too (of course, this is just an example, real data can come from a a database or other type of persistent storage):
var item1 = <GanttChartItem>{ content: 'My summary task' };
var item1 = <GanttChartItem>{ content: 'My summary task' };
var item2 = <GanttChartItem>{ content: 'My standard task', indentation: 1,
start: new Date(2023, 10-1, 16, 8, 0, 0), finish: new Date(2023, 10-1, 17, 16, 0, 0),
completedFinish: new Date(2023, 10-1, 17, 10, 0, 0), assignmentsContent: 'My resource' };
var item3 = <GanttChartItem>{ content: 'My milestone', indentation: 1,
start: new Date(2023, 10-1, 18, 16, 0, 0), isMilestone: true };
item3.predecessors = [{ item: item2 }];
this.items = [ item1, item2, item3 ];
  • a settings object that manages the way the component displays and manipulates the bound data; here you can set up the chart scales to use, the colors of all bars, either as inline style strings or, better, as class names mapping SCSS definitions, and even define SVG element templates for bars and dependency lines as functions, or miscellaneous event handlers that are not directly supported through the Angular API; this example is limited to defining some CSS classes, but our component’s reference documentation describes all possible values you can set:
this.settings = { 
containerClass: 'container',
standardItemClass: 'task',
milestoneItemClass: 'milestone',
summaryBarClass: 'summaryBar',
standardBarClass: 'standardBar',
standardCompletedBarClass: 'standardCompletedBar',
milestoneBarClass: 'milestoneBar',
dependencyLineClass: 'dependencyLine',
assignmentsClass: 'assignments',
};
  • an onItemChanged function to be called automatically when the user modifies items in the graphical interface, such as upon dragging bars around or creating dependencies, so that you can record subsequent changes and submit them to your server side, for example, to store them in the source database; in this example we only log the changes in the console:
this.onItemChanged = (item, propertyName, isDirect, isFinal) => {
console.log(propertyName + ' changed for ' + item.content + '.');
}`
  • a style string, to setup, for example, a fixed height on the div that will eventually contain the inner component;
  • and a license string, which can remain null while using the library in trial mode, but which should eventually be replaced with a license value if you’d eventually purchase the underlying JavaScript based DlhSoft product that these Angular extensions reuse.

Now let’s not continue unless we first define the CSS classes indicated within settings. Assuming we use SCSS, we need to either define them into the global styles.css file (at root level of our Angular project):

.container {
font-weight: bold;
color: brown;
}
.summaryBar {
fill: lightcoral;
}
.standardBar {
fill: lightBlue;
stroke: royalblue;
stroke-width: 0.75;
}
.standardCompletedBar {
fill: royalblue;
stroke-width: 0;
}
.milestoneBar {
fill: lightgreen;
stroke: green;
stroke-width: 0.75;
}
.dependencyLine {
stroke: royalblue;
stroke-width: 0.75;
fill: none;
marker-end: url(#ArrowMarker);
}
.assignments {
fill: royalblue;
}

… and/or define them in app.component.scss within a ng-deep section (required because the underlying JavaScript component itselfisn’t aware of the Angular structure):

::ng-deep {

.task {
background-color: lightblue;
}
.milestone {
background-color: lightyellow;
}

}

Our Angular component can include other UI elements, of course. Such as buttons to trigger changes in our component’s settings, for example. Here below we define a way for the end user to change the chart area’s scales on demand.

Note that in order to be able to access the component on the fly, we need an ElementRef defined first (in app.component.ts):

  @ViewChild('ganttChartView', { read: ElementRef, static: true }) ganttChartViewRef: ElementRef;
ganttChartView: GanttChartView.Element;

Then, in the component’s HTML, we can have the component referenced using a # char:

  <ganttchartview #ganttChartView
[items]="items" [settings]="settings" [license]="license"
[change]="onItemChanged" style="min-height: 388px; width: 100%;">

</ganttchartview>

In TypeScript, you will initialize the reference during the ngOnInit call:

ngOnInit() {
this.ganttChartView = <GanttChartView.Element>(<HTMLElement>this.ganttChartViewRef.nativeElement).firstChild;
}

Finally, we can have now further HTML to define a selector for scale types, e.g.:

  <select [(ngModel)]="scaleType" (ngModelChange)="onScaleChanged()">
<option value="Years">Years + months</option>
<option value="Months">Months + weeks</option>
<option value="Weeks">Weeks + days</option>
<option value="Days">Days + hours</option>
</select>

… and onScaleChanged function can be defined back in TypeScript, like this:

this.onScaleChanged = () => {
this.settings.scales[1].scaleType = this.scaleType;
switch (this.scaleType) {
case 'Years':
this.settings.scales[1].headerTextFormat = 'Year';
this.settings.scales[2].scaleType = 'Months';
this.settings.scales[2].headerTextFormat = 'Month';
this.settings.hourWidth = 1;
break;
case 'Months':
this.settings.scales[1].headerTextFormat = 'MonthYear';
this.settings.scales[2].scaleType = 'Weeks';
this.settings.scales[2].headerTextFormat = 'Date';
this.settings.hourWidth = 2.5;
break;
case 'Weeks':
this.settings.scales[1].headerTextFormat = 'Date';
this.settings.scales[2].scaleType = 'Days';
this.settings.scales[2].headerTextFormat = 'DayOfWeekAbbreviation';
this.settings.hourWidth = 5;
break;
case 'Days':
this.settings.scales[1].headerTextFormat = 'Date';
this.settings.scales[2].scaleType = 'Hours';
this.settings.scales[2].headerTextFormat = 'Hour';
this.settings.hourWidth = 25;
break;
}
this.ganttChartView.refresh();
}

As you can see, the code simply changes settings object as needed, and performs a refresh() call on the JavaScript component for its UI to adapt. That’s all!

Note: You can download the full sample app with source from here.

--

--