Introduction to BidiModule in Angular CDK

Angular CDK provides great common features that we developers can use to make our applications better. They can be amazing base for our future components.

Photo by Carl Newton on Unsplash

Motivation

You may want support different languages in your application and one of this language can be RTL, such as: Arabic, Hebrew or Persian. For that, your application need to know which current direction in selected language is used RTL or LTR.

Using BidiModule

Firstly, we need to install package to use it in your existing Angular application by using this command:

ng add @angular/material

This command automatically update your package.json file and install all required dependencies including @angular/cdk.

Next step is importing BidiModule into your AppModule:

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

Okay, we setup our project to using BidiModule features!

Querying current direction

We can query which current direction document has by injecting Directionality service and reading its value property.

import { Component } from '@angular/core';import { Directionality, Direction } from '@angular/cdk/bidi';
@Component({
selector: 'app',
template: '<p>Current direction is: {{ direction }}!</p>',
})
export class AppComponent {
public constructor(
private readonly dir: Directionality,
) {
this.direction = dir.value;
}
public direction: Direction;
}

In this case we inject Directionality and request its value property to assign our direction property for displaying it in template.

Direction type can have only two possible values:

export type Direction = 'ltr' | 'rtl';

Directionality service under the hood injects DOCUMENT token to get current’s document dir attribute on body or documentElement properties which is <body> and <html> tags. If dir attribute exists at <body> element then <html> element is ignored and if dir attribute are not presented or doesn’t match with one of two possible values of Direction type, default value assigned as ltr.

Subscribing to direction changes

You can also track dir attribute changes subscribing to change EventEmitter<Direction> of Directionality service!

import { Component } from '@angular/core';
import { Observable } from 'rxjs';
import { Directionality, Direction } from '@angular/cdk/bidi';@Component({
selector: 'app',
template: '<p>Current direction is: {{ direction | async }}!</p>',
})
export class AppComponent {
public constructor(
private readonly dir: Directionality,
) {
this.direction = dir.change;
}
public direction: Observable<Direction>;
}

We use AsyncPipe to subscribe into Observable, so we don’t need think about unsubscription and write another boilerplate code. We just get current document direction and displaying it in our component template.

Another great use case

We can easily add dir attribute to our document.

import { Component, Inject, OnDestroy } from '@angular/core';
import { DOCUMENT } from '@angular/platform-browser';
import { Subscription } from 'rxjs';
import { Directionality, Direction } from '@angular/cdk/bidi';
@Component({
selector: 'app',
template: '<some-cmp></some-cmp>',
})
export class AppComponent implements OnDestroy {
public constructor(
private readonly dir: Directionality,
@Inject(DOCUMENT) private readonly document: Document,
) {
this.direction = dir.change.subscribe((direction: Direction) =>
{
this.document.dir = direction;
});

}
public direction$: Subscription = Subscription.EMPTY; public ngOnDestroy(): void {
this.direction$.unsubcribe();
}

}

Conclusion

Big thanks for reading this article! I hope this was helpful for you! Another articles will be coming!