僕がAngularアプリケーションを書くときに頻出する実装パターンを紹介する記事です。続くかどうかは未定です。
onDestroy$
ngOnDestroyメソッドが呼び出されたタイミングでemitされるEventEmitterを作っておき、RxJSのtakeUntilパイプなどで使う実装パターン。
ngOnDestroyメソッド内でunsubscribeメソッドを呼び出すよりも宣言的で意味が取りやすいし、忘れにくい。
実装例はこんな感じ。ReactiveFormsModuleを使うときにvalueChangesに引っ掛けることが多い。
import { Component, OnDestroy, OnInit, EventEmitter, Output } from '@angular/core';
import { FormGroup, FormControl } from '@angular/forms';
import { takeUntil } from 'rxjs/operators';
@Component({
selector: 'app-form',
template: `
<form [formGroup]="form">
<input formControlName="name">
</form>
`
})
export class FormComponent implements OnDestroy {
@Output() valueChange = new EventEmitter<any>();
readonly form = new FormGroup({
name: new FormControl(),
});
private readonly onDestroy$ = new EventEmitter();
constructor() {
this.form.valueChanges
.pipe(
takeUntil(this.onDestroy$),
)
.subscribe(value => {
this.valueChange.emit(value);
});
}
ngOnInit() {
this.form.patchValue({
name: 'Angular 5'
});
}
ngOnDestroy() {
this.onDestroy$.emit();
}
}
https://stackblitz.com/edit/angular-vdnrbp
MaterialModule
Angular Materialのモジュールを束ねるための中間モジュールを作るパターン。
使っているモジュールが一箇所でわかるのと、TestBedに依存モジュールとして渡すのが楽になるので有用。
DI経由でグローバルに適用するAngular Materialの設定もここにまとめられるのでわかりやすい。
import { NgModule } from '@angular/core';
import {
MatButtonModule,
MatCardModule,
} from '@angular/material';
import { PortalModule } from '@angular/cdk/portal';
import { OverlayModule } from '@angular/cdk/overlay';
export const modules = [
MatButtonModule,
MatCardModule,
OverlayModule,
PortalModule,
];
@NgModule({
imports: [...modules],
exports: [...modules],
providers: [
{
provide: MAT_LABEL_GLOBAL_OPTIONS,
useValue: {
float: 'always',
},
},
],
})
export class MaterialModule {}
safeHtmlパイプ
これはみんな書くでしょ、って気がする。与えられた文字列を安全なHTMLですよ、とマーキングしてAngularに渡すお仕事。
import { Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
@Pipe({
name: 'safeHtml',
})
export class SafeHtmlPipe implements PipeTransform {
constructor(private sanitizer: DomSanitizer) {}
transform(value: string): any {
return this.sanitizer.bypassSecurityTrustHtml(value);
}
}
provideXXX関数
サービスのプロバイダを関数としてエクスポートして、モジュール側で関数を呼び出すパターン。
何をprovideしているかがわかりやすい。
複数のサービスを一気にプロバイドする場合、特に順序が重要になるHTTP_INTERCEPTORSのようなmultiなプロバイダにおいて、モジュール側にそれを意識させずに済むのが気に入ってる。
export function provideHttpInterceptor() {
return [
{
provide: HTTP_INTERCEPTORS,
useClass: AuthorizationHeaderInterceptor,
multi: true,
},
{
provide: HTTP_INTERCEPTORS,
useClass: CredentialInterceptor,
multi: true,
},
];
}
import { provideHttpInterceptor } from './config/http';
@NgModule({
...
providers: [
provideHttpInterceptor(),
],
})
export class CoreModule {}
書いてみるとそれほど種類がないなという気がしてきたので、次回は未定です。