Angular (4)で設定したLocale IDを取得
LOCALE_ID
を利用。
以下のようにAOTでコンパイルしていない場合、初期値のen-US
になります。
ng serve --aot --locale ja
import { Component, OnInit, LOCALE_ID, Injector } from '@angular/core'; export class FooComponent implements OnInit { constructor(private injector: Injector) { } ngOnInit() { const locale = this.injector.get(LOCALE_ID); // -> 'ja' } }
雑メモはGist (Lepton) に
プログラムに関する備忘録をこのブログに書いていましたが、それくらいの文章やコードならGistにあげればいいのかと思い始めました。
Leptonというアプリがあるのでしばらくそれを使ってみようかと思います。
Quiver、SnippetsLabなど他のアプリも試してみましたが、今のところLeponが自分の用途にはあってそうです。
- Lepton
- GIstのクライアントアプリ
- 無料
- Quiver
- SnippetsLab
以下ページも参考になりそうです。
AngularのTemplate Syntax
Angular - Template Syntaxを読んだメモです。
(v4.3.6対応)
- Binding一覧
- Operator一覧
- Built-in attribute directives
- Two-way
- *ngForのtrackByを使って描画対象かどうかを判断する
- Template reference variables ( #var )
- その他
Binding一覧
<!-- Property -->https://angular.io/guide/template-syntax <img [src]="heroImageUrl"> <hero-detail [hero]="currentHero"></hero-detail> <greeting message="hello"></greeting><!-- プロパティが文字列かつテンプレートに直接埋め込む場合 --> <!-- Attribute --> <tr><td [attr.colspan]="1 + 1">One-Two</td></tr> <!-- Class --> <div class="bad curly special" [class]="badCurly">Bad curly</div><!-- `badCurly`で上書きされる --> <div [class.special]="isSpecial">The class binding is special</div><!-- 特定のクラスのon/off --> <!-- Style --> <button [style.color]="isSpecial ? 'red': 'green'">Red</button> <button [style.font-size.em]="isSpecial ? 3 : 1" >Big</button> <!-- Event --> <button (click)="onSave()">Save</button>
参考
- https://angular.io/guide/template-syntax#property-binding–property-
- https://angular.io/guide/template-syntax#attribute-class-and-style-bindings
- https://angular.io/guide/template-syntax#event-binding—event-
Operator一覧
<!-- Pipe --> <div>Title through uppercase pipe: {{title | uppercase}}</div> <!-- Safe navigation operator (`?.`) --> The null hero's name is {{nullHero?.name}} <!-- Non-null assertion operator (`!`)--> <div *ngIf="hero"> The hero's name is {{hero!.name}} </div>
参考
- https://angular.io/guide/template-syntax#template-expression-operators
- http://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-0.html#non-null-assertion-operator
Built-in attribute directives
ngClass
- 複数のクラスを管理する場合に有効
<div [ngClass]="currentClasses"></div>
- https://angular.io/guide/template-syntax#ngClass
ngStyle
- 複数のインラインスタイルを管理する場合に有効
<div [ngStyle]="currentStyles"></div>
- https://angular.io/guide/template-syntax#ngStyle
ngModel
Two-way
export class SizerComponent { @Input() size: number | string; @Output() sizeChange = new EventEmitter<number>(); ... resize(delta: number) { this.sizeChange.emit(this.size); } }
<!-- 以下コードは同じ結果になる --> <my-sizer [size]="fontSizePx" (sizeChange)="fontSizePx=$event"></my-sizer> <my-sizer [(size)]="fontSizePx"></my-sizer>
*ngForのtrackBy
を使って描画対象かどうかを判断する
Template reference variables ( #var )
- https://angular.io/guide/template-syntax#template-reference-variables–var-
A template reference variable is often a reference to a DOM element within a template. It can also be a reference to an Angular component or directive or a web component.
その他
DOM propertyとは
- https://angular.io/guide/template-syntax#html-attribute-vs-dom-property
Attributes are defined by HTML. Properties are defined by the DOM (Document Object Model). * > Attributes initialize DOM properties and then they are done. Property values can change; attribute values can’t.
- HTML attribute と DOM property - Please Sleep
Template expressions/statementsで利用できないJS構文
- expressions
- statements
- https://angular.io/guide/template-syntax#template-statements
The template statement parser differs from the template expression parser and specifically supports both basic assignment (
=
) and chaining expressions (with;
or,
).
- https://angular.io/guide/template-syntax#template-statements
Template expressionsのガイドライン
- https://angular.io/guide/template-syntax#expression-guidelines
No visible side effects
Quick execution
Simplicity
Idempotence (冪等性)
AngularのForm(Reactive Forms)メモ
ryotah.hatenablog.com 別記事でこんなのも書きました。
(Angular v.4.3.6を利用)
Reactive Formとは
Template-driven Formsとの比較
- Template-driven Forms
ngModel
のようなディレクティブを利用して、フォーム要素とデータモデルを紐づける。(FormControl
は自動で生成されている。)入力内容が変更されるとミュータブルなデータモデルが更新される。
- Reactive Form
- 最初に
FormControl
のツリーを生成する。フォームとの紐付けはformControlName
プロパティなどでおこなう。
- 最初に
Template-driven Forms
<form #heroForm="ngForm"> <input type="text" [(ngModel)]="model.name" name="name"> </form>
Reactive Forms
<form [formGroup]="heroForm"> <input formControlName="name"> </form>
import { FormControl, FormGroup } from '@angular/forms'; ... heroForm = new FormGroup({ name: new FormControl() });
- https://angular.io/guide/reactive-forms#reactive-forms-1
One advantage of working with form control objects directly is that value and validity updates are always synchronous and under your control.
- https://angular.io/guide/reactive-forms#async-vs-sync
Reactive forms are synchronous. Template-driven forms are asynchronous.
主要4クラス
- AbstractControl
- 基本クラス。他3クラスはこの抽象クラスをextendsしている。
- FormControl
- 個々のフォーム要素(
<input>
など)の値と有効性の状態を追跡
- 個々のフォーム要素(
- FormGroup
AbstractControl
のグループの値と有効性の状態を追跡
- FormArray
AbstractControl
の配列の値と有効性の状態を追跡
FormGroup
, FormArray
を利用した例
<form [formGroup]="heroForm"> <div> <label>Name: <input formControlName="name"> </label> </div> <!-- アドレスの数は可変 --> <div formArrayName="addresses"> <div *ngFor="let address of addresses.controls; let i=index" [formGroupName]="i"> <div><b>Address {{i + 1}}</b></div> <label>City: <input formControlName="city"> </label> </div> </div> <button (click)="addAddress()">add</button> </form> <pre>Form value: {{ heroForm.value | json }}</pre> <pre>Form status: {{ heroForm.status | json }}</pre>
heroForm: FormGroup; constructor(private fb: FormBuilder) { // `FormBuilder`を利用した`FormGroup`の生成 // https://angular.io/guide/reactive-forms#introduction-to-formbuilder this.heroForm = this.fb.group({ name: '', addresses: this.fb.array([]), }); } addAddress() { this.addresses.push(this.fb.group({ city: '' })); } get addresses(): FormArray { // 個々の`FormControl`, `FormGroup`, `FormArray`は `get`で取得する // https://angular.io/guide/reactive-forms#inspect-formcontrol-properties return this.heroForm.get('addresses') as FormArray; }
フォームの値を変更する
- AbstractControl#setValue
- AbstractControl#patchValue
- AbstractControl#reset
- FormGroup#setControl
- 既にあるcontrolを置き換える
- FormArray#setControl
- 既にあるcontrolを置き換える
フォームの変更を監視する
const nameControl = this.heroForm.get('name'); nameControl.valueChanges.forEach( (value: string) => console.log(value) );
データモデルとフォームモデル
- データモデルを使いフォームモデル(
FormControl
)を作成 - ユーザー操作の結果、更新されるのはフォームモデル
- Submitなどのタイミングでフォームモデルから送信用のデータモデルを作成
- データモデルとフォームモデルの構造は一緒である必要はない(当然、似ている方が楽ではあるが)
バリデーション
(あとで追記)
AngularのForm(Template-driven Forms)メモ
(Angular v.4.3.6を利用)
<select>
を利用する
*ngFor
を利用する- AngularJSの
ng-options
のようなものはない
- AngularJSの
<select [(ngModel)]="model.power" name="power"> <option *ngFor="let pow of powers" [value]="pow">{{pow}}</option> </select>
NgFormとは
- https://angular.io/guide/forms#the-ngform-directive
Angular automatically creates and attaches an
NgForm
directive to the<form>
tag.
- https://angular.io/api/forms/NgForm
Creates a top-level FormGroup instance and binds it to a form to track aggregate form value and validation status.
<form #heroForm="ngForm">
ngModelとname属性
NgModel
インスタンスを取得
- template reference variableを利用する
<input type="text" [(ngModel)]="model.name" name="name" #name="ngModel">
参考
- https://angular.io/api/forms/NgModel
NgModel
はNgControl
をextendsしたもの- exportAsプロパティが'ngModel'
Directive({ selector: '[ngModel]:not([formControlName]):not([formControl])', providers: [formControlBinding], exportAs: 'ngModel' })
バリデーション
- https://angular.io/guide/form-validation#template-driven-validation
you add the same validation attributes as you would with native HTML form validation.
You can then inspect the control's state by exporting
ngModel
to a local template variable.
<input>
関連その他
参考
<input>
操作時のイベントを取得したい
<input (keyup)="onKey($event)">
$event
オブジェクトのプロパティはDOMイベントのタイプによって変わる
値の確認
onKey(event: KeyboardEvent) { console.log((<HTMLInputElement>event.target).value); }
$event
を利用せずに値を確認
(DOMイベント全体を渡さずに、値だけを渡したい。)
<!-- template reference variables を利用 --> <input #box (keyup)="onKey(box.value)">
キーイベントをフィルタリングしたい
<!-- Enterキーに反応 --> <input #box (keyup.enter)="onEnter(box.value)">
Angular Routerメモ
(Angular v.4.3.6を利用)
- 参考
- リンクを設定したい
- ts内で遷移の制御をしたい
- コンポーネント内でパラメータを取得したい
- 特定のRouteに紐付けないパラメータを利用したい
- 前回のURLを取得したい
- アプリ初期時に処理を追加したい
- Routerのナビゲーションイベントを確認したい
- コンポーネントの再利用について知りたい
- RouterとActivatedRouteについて知りたい
- その他
参考
リンクを設定したい
routerLink
を利用
通常
<a routerLink="/path">link</a> <!-- relative routerLink --> <a routerLink="./path">link</a>
パラメータがついたリンク
<!-- route param (/path/1) --> <a [routerLink]="['/path', 1 ]">link</a> <!-- matrix param (/path;matrixParam=value) --> <a [routerLink]="['/path', { matrixParam: 'value' } ]">link</a> <!-- query param (/path?page=1) --> <a [routerLink]="['/path']" [queryParams]="{ page: 1 }">link</a>
アンカー(#)がついたリンク
<!-- fragment (/path#anchor) --> <a [routerLink]="['/path']" fragment="anchor">link</a>
アクティブなリンクにクラスを設定したい
routerLinkActive
を利用
<a routerLink="/path" routerLinkActive="active">link</a> <a routerLink="/path" routerLinkActive="active" [routerLinkActiveOptions]="{ exact: true }">link</a> <a routerLink="/path" [routerLinkActive]="['active', 'border']">link</a>
ts内で遷移の制御をしたい
- コンポーネント、サービス内で制御したい時
Router#navigate
を利用
通常
this.router.navigate(['/path']); // relative link this.router.navigate(['path'], { relativeTo: this.route });
パラメータをつける
// route param (/path/1) this.router.navigate(['path', '1'], { relativeTo: this.route }); // matrix param (/path;matrixParam=value) this.router.navigate(['/path', { matrixParam: 'value' }]); // query param (/path?page=1) this.router.navigate(['/path'], { queryParams: { page: 1 } });
アンカー(#)をつける
// fragment (/path#anchor) this.router.navigate(['/path'], { fragment: 'anchor' });
クエリを保存して遷移したい
NavigationExtras#queryParamsHandling
を利用- https://angular.io/api/router/NavigationExtras#queryParamsHandling
preserve
,merge
が利用できる
- その他にも
NavigationExtras
を利用して、「ヒストリーにpushしない」「ヒストリーを置き換える」などの設定が可能
参考
コンポーネント内でパラメータを取得したい
Observableで取得
constructor(private route: ActivatedRoute) {} ngOnInit() { /** * Routeの設定が { path: 'view/:id' } * URLが /view/10;matrixParam=value?page=1 の場合 */ this.route.paramMap .subscribe((params: ParamMap) => { // params.keys.forEach(key => { const routeParam = params.get('id'); // -> 10 const matrixParam = params.get('matrixParam'); // -> value // }); }); this.route.queryParamMap .subscribe((params: ParamMap) => { const queryParam = this.route.snapshot.queryParamMap.get('page'); // -> 1 }); }
route.snapshot
から取得
constructor(private route: ActivatedRoute) {} // ... /** * Routeの設定が { path: 'view/:id' } * URLが /view/10;matrixParam=value?page=1 の場合 */ const routeParam = this.route.snapshot.paramMap.get('id'); // -> 10 const matrixParam = this.route.snapshot.paramMap.get('matrixParam'); // -> value const queryParam = this.route.snapshot.queryParamMap.get('page'); // -> 1
this.route.snapshot
はActivatedRouteSnapshot
- 初期データしか利用しない場合に利用
特定のRouteに紐付けないパラメータを利用したい
- クエリパラメータを利用
- https://angular.io/guide/router#query-parameters-and-fragments
In the route parameters example, you only dealt with parameters specific to the route, but what if you wanted optional parameters available to all routes? This is where query parameters come into play.
ルートパラメータの例では、ルートに固有のパラメータのみを扱いますが、オプションのパラメータをすべてのルートで使用できるようにしたい場合はどうなりますか?ここでクエリパラメータが有効になります。
- https://angular.io/guide/router#query-parameters-and-fragments
前回のURLを取得したい
アプリ初期時に処理を追加したい
- (Routerとは直接関係ないけど)
APP_INITIALIZER
を利用- 設定ファイルのロードや権限確認などに利用できそう
@NgModule({ providers: [ { provide: APP_INITIALIZER, useFactory: (sites:SitesService) => () => sites.load(), deps: [SitesService], multi: true, } ] }) export class AppModule { }
@Injectable() export class SitesService { constructor() { } load(): Promise<any> { return new Promise((resolve, reject) => { setTimeout(() => { // doing something // ... resolve(); }, 3000); }); } }
参考
- https://angular.io/api/core/APP_INITIALIZER
A function that will be executed when an application is initialized.
- What is best way to load json settings from the server? · Issue #9047 · angular/angular
- Hook into Angular Initialization Process – Hacker Noon
Routerのナビゲーションイベントを確認したい
Router.events
を利用- イベント一覧
constructor(private router: Router) { // 遷移開始時のイベントを確認 router.events.subscribe(event => { if (event instanceof NavigationStart) { console.log(event); // リダイレクトさせることも(一応)可能 // if (event.url !== '/view-a') { // router.navigate(['view-b']); // } } }); }
その他
- イベントのログをコンソールで確認(デバッグ用)
RouterModule.forRoot(appRoutes, { enableTracing: true })
コンポーネントの再利用について知りたい
routeConfig
が同じならコンポーネントは再利用される- パラメータが変わっても再描画はされない
// https://github.com/angular/angular/blob/54e02449549448ebab6f255f2da0b4396665c6f0/packages/router/src/route_reuse_strategy.ts#L66 shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean { return future.routeConfig === curr.routeConfig; }
カスタマイズしたい
RouteReuseStrategy
を利用して挙動を変更できる
参考
- Force reload/refresh current route with RouteReuseStrategy · Issue #13831 · angular/angular
- Angular 2 Component Reuse Strategy – Julia Passynkova – Medium
RouterとActivatedRouteについて知りたい
- Angular Router: Understanding Router State – Angularを読むといいと思います
Any component instantiated by the router can inject its ActivatedRoute.
ActivatedRoute provides access to the url, params, data, queryParams, and fragment observables.
その他
複数のRouteを表示したい
<router-outlet></router-outlet> <!--popupという名前のoutletを設定 --> <router-outlet name="popup"></router-outlet> <!-- `path: 'compose'`に紐づけられているコンポーネントを表示 --> <a [routerLink]="[{ outlets: { popup: ['compose'] } }]">Contact</a>
// `path: 'compose'`に紐づけられているコンポーネントを表示 this.router.navigate([{ outlets: { popup: 'compose' } }]); // null でクリアできる this.router.navigate([{ outlets: { popup: null }}]);
「遷移前に認証チェックをしたい」「遷移前に未保存のデータがあるか確認をしたい」など
CanActivate
,CanActivateChild
,CanDeactivate
を利用
遷移前にデータを読み込みたい
Resolve
を利用Observable
,Promise
(あるいは同期データ)を返すresolve
を定義する- https://angular.io/guide/router#fetch-data-before-navigating
- 読み込んだデータは
ActivatedRoute#data
やActivatedRoute#snapshot.data
から取得する- https://angular.io/api/router/ActivatedRoute#data
*(Routeで設定した
data
と同じように扱えるようになる)
- https://angular.io/api/router/ActivatedRoute#data
*(Routeで設定した
遅延読み込み
基本設定
- https://angular.io/guide/router#lazy-loading-route-configuration
loadChildren: 'app/admin/admin.module#AdminModule'
読み込み開始前にガードしたい
canLoad
を利用
プリロードさせたい
preloadingStrategy
を利用
RouterModule.forRoot( appRoutes, { // PreloadAllModules // https://angular.io/api/router/PreloadAllModules // guardされていないrouteが全てプリロードされる preloadingStrategy: PreloadAllModules } )
- PreloadingStrategyをカスタムすることも可能
@Injectable() export class CustomPreloadingStrategy implements PreloadingStrategy { preload(route: Route, load: () => Observable<any>): Observable<any> { // routeの設定情報に `data: { preload: true }` があればプリロードする if (route.data && route.data['preload']) { return load(); } else { return Observable.of(null); } } }
Angular CLIでビルドされたファイルの容量を把握する
把握
--stats-json
オプションを有効にしてstats.json
を出力ng build --prod --stats-json
- https://github.com/angular/angular-cli/wiki/build
webpack-bundle-analyzer
を利用
–build-optimizer
容量の把握の話とは関係ないですが、Angular CLI 1.3から--build-optimizer
が導入されています。
ng build --prod --build-optimizer