5.20231.904
5.20231.904

Angular Components

  • Supports Angular version 2.2.1 or higher, including 10.* versions.

Wijmo components for Angular allow you to use Wijmo controls in Angular templates markup. In terms of the TypeScript class inheritance feature, Wijmo Angular components "extend" the control classes they represent. This means that when you acquire a reference to a Wijmo component, the referenced instance is a Wijmo control with all its properties, events and methods, and an Angular component at the same time. A Wijmo component extends a control class and adds the necessary functionality that allows the control to be used in the Angular template markup, with the fully functional one-way and two-way property bindings and event bindings. This integration is smooth, as all the players, Wijmo controls, Wijmo Angular components and Angular itself are written in the same TypeScript language.

Wijmo Angular 2 components are shipped as a set of npm packages, one package per core library package, with the "angular2" word in their names. For example, "wijmo.angular2.grid" package represents components for controls from the core "wijmo.grid" package. The packages can be installed separately, or all together using the "@grapecity/wijmo.angular2.all" group package:

npm install @grapecity/wijmo.angular2.all

See this topic for more details about Wijmo npm packages.

After that you can import modules using ESM import statements. For example, this import statement imports the content of the "wijmo.angular2.grid" module:

import * as wjGrid from '@grapecity/wijmo.angular2.grid';

Angular CLI

Refer to this blog for the step by step instructions.

Importing Wijmo components

With this setup, you may import Wijmo Angular modules and use the components and directives they contain. For example, this code adds a WjFlexGrid component to MyCmp component's template, with the flex property containing a reference to the added grid:

import { Component, NgModule, ViewChild } from '@angular/core';
import { WjGridModule, WjFlexGrid } from '@grapecity/wijmo.angular2.grid';

@Component({
    template: '<wj-flex-grid #flex [itemsSource]="data"></wj-flex-grid>',
    selector: 'my-cmp',
})
export class MyCmp {
    data: any[];
    @ViewChild('flex') flex: WjFlexGrid;

}

@NgModule({
    imports: [WjGridModule, BrowserModule],
    declarations: [MyCmp]
})
export class MyModule {
}

Every Wijmo for Angular JavaScript module contains an Angular NgModule that exports all the components in the module. To use any of these components in your NgModule components' templates, you just need to add a reference to Wijmo NgModule to the imports metadata property of your NgModule decorator.

A name of NgModule is constructed from its JavaScript module name using the following schema:
Wj(JS module name without wijmo.angular2 prefix)Module

For example, WjInputModule NgModule for wijmo.angular2.input JavaScript module, or WjGridFilterModule NgModule for wijmo.angular2.grid.filter JavaScript module.

Adding Wijmo CSS

For Wijmo controls to look and work correctly, you need to load Wijmo CSS files into your application. The styles are shipped in the @grapecity/wijmo.styles npm package. There are two main css files:

  • wijmo.css - includes styles for all Wijmo controls
  • wijmo-core.css - truncated version of wijmo.css, which doesn't include styles for Enterprise controls.

You can load styles in your Angular CLI application in the one of the following places, according to your preference:

In the default styles.css file

Just add this css import statement at the top of the file:

@import '@grapecity/wijmo.styles/wijmo.css';

In angular.json

Add path to the wijmo.css file into the projects.architect.build.options.styles field, along with other css files used in your application:

"styles": [
    "node_modules/@grapecity/wijmo.styles/wijmo.css",
    "src/styles.css"
],

Note that you should specify the relative path to the file here, which includes the nodemodules_ folder. It's recommended to add wijmo.css file before application css files in the styles array. This ensures that your css rules that customize wijmo components are applied correctly.

Creating Wijmo controls in code

Wijmo components for Angular are intended for a usage in templates markup. If you want to create a Wijmo control in code, you should use a Wijmo control from a core module for this purpose, instead of a component. A core module has the same name as a corresponding Angular interop module, but without the "angular2" word in the name. For example, this code creates a FlexGrid control in code:

import { FlexGrid } from '@grapecity/wijmo.grid';
let flex = new FlexGrid('#host_element');

Note that we import FlexGrid control instead of WjFlexGrid component, and import it from the '@grapecity/wijmo.grid' module instead of '@grapecity/wijmo.angular2.grid'.

Angular Markup Syntax

Wijmo Angular components use consistent naming conventions for specifying them in template markup. The HTML element and attribute names used for components can be easily inferred from component class and member names by using the following simple rules:

  • HTML element name representing a Wijmo component is specified using lower-case-dash syntax. For example, WjInputNumber component should be spelled as wj-input-number:
    <wj-input-number [(value)]="amount"></wj-input-number>
  • Wijmo attribute directives use camel case form for their class names, that is, it is a class name with the first letter in lower case. For example, WjFlexGridCellTemplate directive is defined using the wjFlexGridCellTemplate attribute:
    <template wjFlexGridCellTemplate [cellType]="'Cell'"></template>
  • Names of the attributes representing Wijmo component properties and events exactly coincide with the property and event names exposed off the component class interface. Property names must be enclosed in square brackets for one-way binding (e.g. [isReadOnly]) and square brackets plus parentheses for two-way binding (e.g. [(value)]). Event names must be enclosed in parentheses (e.g. (valueChanged)). For example:
    <wj-input-number 
        [(value)]="amount" // two-way binding to a component property
        [format]="'n0'" // one-way binding to string
        [isReadOnly]="true" // one-way binding to boolean
        (valueChanged)="valueChanged($event)"> // event binding
    </wj-input-number>

Note that binding expression should evaluate to a value of the same type as the property type it is assigned to. In the above example, the format string type property is assigned with 'n0' enclosed in single quotes, which represents a string literal. If we omit quotes and just specify n0, then such an expression will be treated as a property name. Similarly, isReadOnly boolean property is bound to true where the latter is specified without quotes, because true is a boolean type constant while 'true' surrounded by single quotes would denote a string literal.

Event binding details

Wijmo event handlers are defined as functions with two parameters: sender and event argument. Angular EventEmitter implementation allows passing of only a single parameter from an event initiator to the subscribers, which is accessible as a value of the $event local variable in template markup. Wijmo events pass an event argument in this parameter. For example:

<wj-flex-grid 
    [itemsSource]="data"
    (deletingRow)="beforeDelete($event)"> // $event contains CellRangeEventArgs object here
</wj-flex-grid>

If you want to additionally receive a sender in an event handler, as it happens when you subscribe to Wijmo control events in TypeScript/JavaScript code, all you need to do is add a local template variable to the component and pass it to the event handler along with the event argument:

<wj-flex-grid #flex // 'flex' local variable references the grid component instance
    [itemsSource]="data"
    (deletingRow)="beforeDelete(flex, $event)"> // pass sender ('flex') and event arguments ($event) to the handler
</wj-flex-grid>

The "initialized" Event

All Wijmo Angular components include an "initialized" event that is raised after the control has been added to the page and initialized.

You can use this event to perform additional initalization in addition to setting properties in markup. For example:

<wj-flex-grid #flex (initialized)="initGrid(flex)">
</wj-flex-grid>
// implementation
export class AppComponent {
    constructor() {
        this.data = ...;
    }

    // add custom merge manager to the FlexGrid
    initGrid(flex) {
        flex.mergeManager = new CustomMerge(flex);
    }
}

Property initialization order in Angular 9 (Ivy) and higher

In Angular 8 and lower, property initialization order was defined internally in the Wijmo components, so independently of the property assignments order specified on the component element, they are always initialized in the same correct order. Technically, the initialization order is driven by the order of the property names in the @Component decorator's inputs property.

The situation has changed in Angular 9, with the advent of the new Ivy compiler, which is used in this framework by default. Now properties are initialized exactly in the order specified on the element by the developer. So, starting with Angular 9, specifying the correct property initialization order is the responsibility of the developer who uses the component.

As an example, let's consider this markup:

<wj-list-box [selectedIndex]="3" [itemsSource]="data"></wj-list-box>

It works correctly in Angular 8 and lower - the list will appear with the fourth item selected. This is not the case in Angular 9 and higher - the list will appear with the first item selected, and the assignment to the selectedIndex property will be ignored. This happens because selectedIndex is defined before itemsSource here, and will be assigned before the control received its items array via the itemsSource property, hence there is no item with index 3 at the moment. In Angular 8 and lower, the initialization order was internally defined by the component, so that selectedIndex is always assigned after itemsSource.

To correct this, and make this markup functional as expected in Angular 9 and all other versions, we need to define selectedIndex after itemsSource:

<wj-list-box [itemsSource]="data" [selectedIndex]="3"></wj-list-box>

Another good example is with the [isRequired]="false" property, which allows a component to accept null values. This markup will raise an exception in Angular 9 (but works in Angular 8):

<wj-input-number [value]="null" [isRequired]="false"></wj-input-number>

This is because an attempt to assign a null value is performed before isRequired was set to false.

The correct definition looks like here:

<wj-input-number [isRequired]="false" [value]="null"></wj-input-number>

This will work in all Angular versions.

Disabling ES Modules in Angular 8 and Lower

ESM versions of wijmo.angular2.* modules are enabled by default as of build 5.20202.699 (released July 22nd 2020). This may cause problems in some specific usage scenarios, in projects based on Angular version 8 or lower. The example of such a use case is where you have a component inherited from Wijmo component, with a custom component template that includes wjFlexGridCellTemplate or wjItemTemplate directives, or Menu components. Note that the problem is caused by the Angular AOT compiler (ViewEngine), so it becomes apparent in production bundles only.

If you get into this problem, you should disable ESM versions of the wijmo.angular2.* modules, which can be achieved using the wijmo-esm utility. Normally you call this utility without passing any options, in this case it automatically detects Angular version used in your project, and disables Wijmo ESM modules if it's 8 or earlier, or enable them if version is 9 or higher. When ESM is disable, Angular will use CommonJS modules.

You can also unconditionally disable or enable ESM modules by specifying a -disable or -enable option. The tool is installed into the nodemodules/.bin_ folder of you project. The recommended way to use it is to call it from the npm "postinstall" event:

    "scripts": {
        "postinstall": "wijmo-esm",
        ..........
    }

If you want to run it manually, add it to the npm scripts of your project's package.json:

    "scripts": {
        "wijmo-esm": "wijmo-esm",
        ..........
    }

After that you can run it using this command:

 npm run wijmo-esm

Or this, if you need to specify an option:

 npm run wijmo-esm -- -disable

To display help information about the available options, run this command:

 npm run wijmo-esm -- -help

The tool's executable is located under this path in your project:

node_modules/@grapecity/wijmo.angular2.directivebase/tools/wijmo-esm.js