Jozef Sakáloš
18 December 2019

Using Bryntum Scheduler in an Angular App

Angular is a TypeScript-based open-source web application framework led by the Angular Team at Google and by a community of individuals and corporations. It uses templates […]

Angular Logo
Angular is a TypeScript-based open-source web application framework led by the Angular Team at Google and by a community of individuals and corporations. It uses templates written in HTML which can include custom tags.

The templates are bound to data prepared, held and processed by TypeScript classes. The data and template are combined to produce dynamically updated views.

The core Angular library does not contain any visual components such as buttons, form fields or grids therefore developers often rely on third party UI libraries. Bryntum Scheduler is a sophisticated scheduling component that can easily be used in any Angular application.

This article will describe how to use Bryntum Scheduler in an Angular application.

Bryntum Scheduler in Angular

The Scheduler itself is framework agnostic, but it ships with demos and wrappers to simplify using it with popular frameworks such as Angular. The purpose of this guide is to give you a basic introduction on how to use Scheduler with Angular.

Several of the Scheduler demos use a wrapper for the Scheduler that turns it into an Angular component. The wrapper is at this point a basic implementation, but feel free to extend it to meet your needs. Supported properties and how to add non-supported ones is described later in this post.

The Scheduler includes demos for several Angular versions. Most of them need to be built before being viewed, please open `examples/angular` and check the demo corresponding to your Angular version.

You can view all Angular demos in our example browser.

The latest examples have been created with ng new example-name so they can be run locally in development mode by invoking:

npm install
npm start

You can also build the production version of an example, or your application, by running:

npm install
npm run build

The built version is then located in dist sub-folder which contains the compiled version that can be deployed to your production server.

Installing the Scheduler NPM package

The Scheduler package contains all the Bryntum Scheduler code together with supporting widgets and utilities in the form of a module that can be installed with `npm` package manager. The package is located in the `build` folder of the unzipped Bryntum Scheduler distribution. Run this code to install it:

npm install --save Scheduler/build

 
Scheduler/build should be the path to the Scheduler’s build folder and it can be a relative path. The result is an entry for bryntum-scheduler in your package.json:

"dependencies": {
    "bryntum-scheduler": "file:../../../../build"
    ... other dependencies
}

 

Integrating Scheduler with Angular using the wrapper

The Scheduler wrapper and wrappers for other supporting components are implemented as an Angular shared library named bryntum-angular-shared located in examples/angular/_shared folder.

Note: You can also copy the source wrapper file from the shared library sources to your project. The wrapper is in examples/angular/_shared/projects/bryntum-angular-shared/src/lib/scheduler.component.ts. If you prefer to copy the wrapper to your project, you can skip the rest of this section.

There are severals steps to execute to use this library in your project:

Then you will be able to use the custom `<bry-scheduler>` tag the same way as you use your application components. Our latest examples are built this way so you can refer to them to see the details of its usage.

Building the bryntum-angular-shared package

Go to the package folder examples/angular/_shared and run:

npm install
npm run build

 

Installing the `bryntum-angular-shared` package

In your project folder run:

npm install --save ../_shared/dist/bryntum-angular-shared

 

Adding the bryntum-angular-shared to tsconfig.json

tsconfig.json is located in the root of your project. For Angular to find the shared library we need to add some paths to the compilerOptions property. We need these paths:

  "paths": {
    "bryntum-angular-shared":[
      "../_shared/dist/bryntum-angular-shared"
    ],
    "@angular/*": [
      "node_modules/@angular/*"
    ]
  }

 
Adjust the above path to bryntum-angular-shared according to the locations of your project and the Scheduler distribution.

Importing the Bryntum Angular Shared Module

Add the following code to your app.module.ts:

import { BryntumAngularSharedModule } from 'bryntum-angular-shared'
@NgModule({
  imports: [
    BryntumAngularSharedModule
  ]
})

 
Note: Our examples import the UMD version of the Scheduler package for IE 11 compatibility. If you do not need to support IE, then edit the scheduler wrapper in examples/angular/_shared/projects/bryntum-angular-shared/src/lib/scheduler.component.ts to import the base version of the package.

Please note that you cannot import both normal and UMD versions of the Scheduler package in one application. The error Bundle included twice means that both UMD and normal version were imported. In this case, revise all your imports and make sure that only one version is used.

Using the wrapper in your application

Now you can use the the wrapper as follows:

<bry-scheduler
    #scheduler
    [columns]           = "schedulerConfig.columns"
    [viewPreset]        = "schedulerConfig.viewPreset"
    (onSchedulerEvents) = "onSchedulerEvents($event)"
    // other properties
></bry-scheduler>

 
You will also have to import the Scheduler CSS files. The best way is to do this in src/styles.scss:

@import "bryntum-scheduler/scheduler.material.css";

// other application-global styling

 

Supported properties

The following properties can be directly bound to the Angular component. They are then passed from it down to the native instance of the Scheduler (schedulerEngine). In the following example, the value of the variable schedulerConfig.events will become schedulerEngine.events:

<bry-scheduler
  [events] = "schedulerConfig.events"
></bry-scheduler>

 

Below is the list of supported config options and properties (the exact list is updated with every release):

Supported features

Features are distinguished from other config options by a Feature suffix. They are mapped to the corresponding feature of the schedulerEngine. In the following example, the value of variable schedulerConfig.stripeFeature will become schedulerEngine.features.stripe:

<bry-scheduler
  [stripeFeature] = "schedulerConfig.stripeFeature"
></bry-scheduler>

 
The list of supported features:

Adding properties which are not supported out of the box

The Scheduler wrapper has a lot of properties which are supported by default. But sometimes you may need to add one that is not supported. For example autoAdjustTimeAxis.

To use an unsupported optoin, you first need to update the wrapper examples/angular/_shared/projects/bryntum-angular-shared/src/lib/scheduler.component.ts:

private configs : string[] = [
    'autoAdjustTimeAxis',
    ...
]

@Input() autoAdjustTimeAxis: boolean;

 

Then you should rebuild the bryntum-angular-shared package. For this you need to go to examples/angular/_shared and run:

npm run build

 

Now, the wrapper has been updated and built, and you can use the new config in your application. Let’s say you want to add it to the Basic demo (examples/angular/basic).

Simply edit examples/angular/basic/src/app/schedulerConfig.js and specify a value:

export default {
    autoAdjustTimeAxis : false, // lets say you want to disable auto adjusting
    ...
};

 

Now add the config option to the template in examples/angular/basic/src/app/app.component.html:

<bry-scheduler
    #scheduler
    [autoAdjustTimeAxis] = "schedulerConfig.autoAdjustTimeAxis"
    ...
></bry-scheduler>

 

The last step is to build the demo and check the result. Go to examples/angular/basic and run

npm run build

 

Accessing the Scheduler engine

If you need to access Scheduler functionality not exposed by the wrapper, you can access the Scheduler engine directly. Within the wrapper it is available as this.schedulerEngine, from the outside it would look something like this:

<bry-scheduler
  #scheduler
></bry-scheduler>
class AppComponent {

  @ViewChild(SchedulerComponent) scheduler:SchedulerComponent;

  onClick() {
    this.scheduler.schedulerEngine.scrollEventIntoView(xx);
  }
}

For more information on what functions are available in the engine, please refer to the API docs.

Integrating Scheduler with Angular directly (without a wrapper)

Although the Scheduler is a very complex and sophisticated component, it is still very easy to use. All the Scheduler needs is:

  1. a configuration object
  2. an element to render to

Scheduler configuration

The best practice is to keep Scheduler configuration in a separate file from which it is imported and passed to the Scheduler constructor. The code would then look similar to the following:

import { Scheduler } from 'bryntum-scheduler';
import schedulerConfig from './schedulerConfig';

schedulerConfig.appendTo = 'container';

const scheduler = new Scheduler(schedulerConfig);

where schedulerConfig.js would contain configuration similar to the following:

export default {
    startDate : '2019-06-21 08:00:00',

    viewPreset : {
      name              : 'weekAndDay',
      displayDateFormat : 'll',
      columnLinesFor    : 'bottom'
    },

    columns : [...]

    // other config options
}

 
To find out more about all the available configuration options of the Bryntum Scheduler, please consult the API docs.

Rendering to an element

The Bryntum Scheduler needs an existing HTML element to render into. It can be declared as any of the appendTo, insertBefore or insertFirst properties with values being either an HTMLElement instance or a string (the id of an existing element). The Scheduler renders itself as during its instantiation if any of the above properties is specified in the config object passed into constructor.

In the above example we assign schedulerConfig.appendTo = 'container', which is the id of the containing element, for example <div id="container"></div>.

If you do not want to render Scheduler immediately, you can omit the above properties and render the component manually at the appropriate time by passing the container to the render method. It would look like this:

import Scheduler from 'bryntum-scheduler';
import schedulerConfig from './schedulerConfig'

// some other code...

const scheduler = new Scheduler(schedulerConfig);

// some other code...

scheduler.render('container');

The most common scenario is to render Scheduler in the ngOnInit method. At this time we already have a valid element into which we can render the Scheduler component. A very simple example of an Angular component doing this would be following:

import { Component, OnInit, ElementRef } from '@angular/core';
import schedulerConfig from './schedulerConfig';
import { Scheduler } from 'bryntum-scheduler';

@Component({
  selector: 'scheduler-view',
  template: '
' }); export class SchedulerViewComponent implements OnInit { private elementRef : ElementRef; public schedulerEngine : any; constructor(element : ElementRef) { this.elementRef = element; } ngOnInit() { const schedulerEngine = new Scheduler({ ...schedulerConfig, appendTo : this.elementRef.nativeElement, }); this.schedulerEngine = schedulerEngine; } }

 
The above component can be used anywhere in your Angular application as <scheduler-view></scheduler-view>.

Updating properties at runtime

If you need, you can implement the ngOnChanges method in the above component that is called by Angular when any of the properties of the component changes. You would then analyze the changes and you would pass them down to schedulerEngine as required by calling its methods or assigning its properties.

Listening to Scheduler events

The last missing piece is listening and reacting to events fired by the Scheduler. For example, listening to selection change as the user clicks on tasks.

You can add listeners on Scheduler by:

The listeners config could look similar to this:

    listeners : {
        selectionchange : (event) {
            console.log(event);
        }
    }

The same effect can be achieved by calling on method on the Scheduler instance:

schedulerEngine.on('selectionchange', (event) => {
    console.log(event);
})

Troubleshooting

In the case of any troubles with building or running of our examples and perhaps also with your application can be often resolved by the following commands in the example or project directory:

rm -rf package-lock.json node_modules # or a Windows equivalent
npm install
npm run build

The error Bundle included twice means that both normal and UMD versions of the Scheduler package were imported somewhere in your application. Please review your code and import either UMD or normal version of the Scheduler but never both. Don’t forget to inspect the shared packages too.

Further reading

Jozef Sakáloš

Development