import { Observable } from 'rxjs/Observable'; import { ErrorObservable } from 'rxjs/Observable/ErrorObservable'; // ... handleError(err): Observable<any>| ErrorObservable { if (/* 何か */) { return Observable.of('ok'); } else { return Observable.throw(err); } }
「テキスト入力 -> 自動で検索開始」を実現するためのRx使い方
- example-app/book.ts at ee0f331bf808525e003efa264b5065964c7f942b · ngrx/example-app · GitHub
- 元ネタ(NgRx4のサンプルアプリより)
シュミレート用サンプルコード
テキスト入力の代わりに、画面クリックで一連の流れが確認できる簡易版コードです。 ブラウザのコンソールで実行させれば、動作確認できます。
(http://reactivex.io/rxjs/などで実行してみてください。)
const sub = new Rx.BehaviorSubject(); const http = () => Rx.Observable.of('{ data }').delay(500); document.addEventListener('click', (e) => { sub.next(e); }); sub.debounceTime(1000) .distinctUntilChanged() .switchMap(() => { console.log('start http'); const next$ = sub.skip(1); return http().takeUntil(next$); }) .subscribe(val => console.log('get', val));
説明
.debounceTime
- 入力中に送信されないようにする
.distinctUntilChanged
- 前回と同じ値を送信しないようにする
.switchMap
- 未完了のhttp通信があった場合、無視する
.takeUntil(next$)
- debounceTimeで遅延させている間にhttp通信が完了する場合があるので、何かしらの入力変更があったらhttp通信を無視できるようにする
9月リンク集
- これは何か
- NgRx, アプリケーションの状態管理
- Rx関連
- Angular関連
- angular - @HostBinding and @HostListener: what do they do and what are they for? - Stack Overflow
- コンポーネントを動的に表示
- Change Detectionについて
- 私がMVCフレームワークをもはや使わない理由
- Running Protractor tests on Webdriver 2.47.1 gets - Error: Server terminated early with status 1 · Issue #2638 · angular/protractor · GitHub
- RouteReuseStrategy
- テスト
これは何か
- 9月に調べたことのメモ。基本形式は、「参考URLとそれに関するメモとコメント」。
- Angular関連がほとんど。
NgRx, アプリケーションの状態管理
A Comprehensive Introduction to @ngrx/store - Companion to Egghead.io Series
- 単純化したngrxの実装をしながら、Rxの機能、Reduxの考えかた、Rxによる実装方法がわかる
- Action -> Reducer -> Stateの流れ、Storeの実装方法、Reducerの合成、ミドルウェアなど
BehaviorSubject
,scan
,let
,distinctUntilChanged
,combineLatest
,withLatestFrom
など- Storeからデータを所得する方法、Store(State)のデータと表示用のデータをどう分けて管理するか #ngrx #angular · GitHub
- 個別のselectで取得, combineLatestでまとめる, projection functionを抽出して別ファイルor関数をつくる
// combine multiple state slices Observable.combineLatest( store.select('people'), store.select('events'), (people, events) => { // projection here })
Using NgRx 4 to Manage State in Angular Applications
- NgRxを使った状態管理について
- アプリケーションのStateを以下6種類に分けて考える
- Server state
- Persistent state
- The URL and router state
- Client state
- Transient client state
- Local UI state
- Using NgRx 4 to Manage State in Angular Applicationsのメモ #angular #rx #ngrx #redux · GitHub
- 日本語メモ
NgRx: Patterns and Techniques – nrwl
- アクションを3種類に分ける
- コマンド、ドキュメント、イベント
- エフェクト
- アクションの決定、アクションの変形、サイドエフェクト
- Reducerがやらないこと全てをおこなう
- NgRx: Patterns and Techniquesのメモ #angular #ngrx #redux #rx · GitHub
- 日本語メモ
platform/README.md at master · ngrx/platform · GitHub
- From Inactive to Reactive with ngrx Brandon Roberts & Mike Ryan - YouTube
- この動画 -> 公式のExampleアプリという順でみると理解しやすい
- https://github.com/ngrx/platform/blob/master/docs/store/README.md
- StoreからStateにアクセス
- StoreはStateのObservableでありActionのObserver
- Actionを受け取り、Stateを返す
- Reducer
export interface ActionReducer<T, V extends Action = Action> { (state: T | undefined, action: V): T; }
- https://github.com/ngrx/platform/blob/master/docs/effects/README.md
- Controlling Effects
- (メモ)
- Controlling Effects
- https://github.com/ngrx/platform/blob/master/docs/router-store/README.md
- どのタイミングでアクションをDispatchしているのか
- https://github.com/ngrx/platform/blob/0528d2ddea5a0a772d7130f7296984e82369961a/modules/router-store/src/router_store_module.ts#L176
(<any>this.router).hooks.beforePreactivation
- https://github.com/ngrx/platform/blob/0528d2ddea5a0a772d7130f7296984e82369961a/modules/router-store/src/router_store_module.ts#L216
this.router.events.subscribe
を利用- こっちは想像通り
- https://github.com/ngrx/platform/blob/0528d2ddea5a0a772d7130f7296984e82369961a/modules/router-store/src/router_store_module.ts#L176
- どのタイミングでアクションをDispatchしているのか
Rx関連
Rxのオペレータメモ #rx · GitHub
- 自分用のメモ
mergeMapとswitchMap
- RxJSのconcatMap, mergeMap, switchMapの違いを理解する(中級者向け) - Qiita
- rxjs - SwitchMap vs MergeMap in the #ngrx example - Stack Overflow
with the switchMap you can cancel the previous network request if it's running?
- 配列を返すことも可能
RxJS を学ぼう #2 – よく使う ( と思う ) オペレータ15選 – NET BIZ DIV. TECH BLOG
Angular関連
angular - @HostBinding and @HostListener: what do they do and what are they for? - Stack Overflow
- @HostBindingと@HostListenerのシンプルな利用例
コンポーネントを動的に表示
- Dynamically add components to the DOM with Angular – Frontend Weekly – Medium
-
@ViewChild('dynamic', { read: ViewContainerRef }) viewContainerRef: ViewContainerRef
read
の存在知らなかった
-
- NgComponentOutlet
- 別の方法
- 表示するだけならこっちの方がシンプルに実装できる
- NgTemplateOutletもある
- angular - What are projectable nodes in angular2 - Stack Overflow
createComponent
の引数であるprojectableNodes
について
- angular4 forms - Load Dynamic templates within a single component using Angular 4 - Stack Overflow
- まだしっかりみてない
ng-template
を取得するためにGetTemplateDirectiveというDirectiveをつくる
Change Detectionについて
- 日本語訳:Angular 2 Change Detection Explained - Qiita
- わかりやすい。ありがたい
- イベント、XHR、タイマー
- Change And Its Detection In JavaScript Frameworks
- Angularに限らない話
markForCheck
とdetectChanges
の違いはわかるがどっちを使うべきかの説明がまだしっくりきていない- ルートからChange Detectionをはじめる
- Everything you need to know about change detection in Angular
Its content is based on the newest Angular version — 4.0.1. The way how change detection mechanism is implemented under the hood in this version is different from the earlier 2.4.1.
私がMVCフレームワークをもはや使わない理由
Running Protractor tests on Webdriver 2.47.1 gets - Error: Server terminated early with status 1 · Issue #2638 · angular/protractor · GitHub
- Macを買い換えたらE2Eのテストがこけてしまった
- 原因はJavaのバージョン
export JAVA_HOME="/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home"
- 原因はJavaのバージョン
RouteReuseStrategy
- 実際にはこのような使い方をしていないがメモとして
/** * コンポーネントの再描画のルールを変更 * https://medium.com/@juliapassynkova/angular-2-component-reuse-strategy-9f3ddfab23f5 */ export class CustomRouteReuseStrategy implements RouteReuseStrategy { // copy from DefaultRouteReuseStrategy shouldDetach(route) { return false; } store(route, detachedTree) { } shouldAttach(route) { return false; } retrieve(route) { return null; } // override shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean { return this._shouldReuseRoute(future, curr) && this.isUnChanged(future, curr); } private _shouldReuseRoute(future, curr) { return future.routeConfig === curr.routeConfig; } /** * 追加ルール * 特定コンポーネントかつ、`key`が変更した時 */ private isUnChanged(future, curr) { const name = future.component && (<any>future.component).name; if (name === 'BarComponent') { if (future.paramMap.get('key') && curr.paramMap.get('key') && future.paramMap.get('key') !== curr.paramMap.get('key')) { return false; } } return true; } }
テスト
selenium - Debugging “Element is not clickable at point” error - Stack Overflow
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などのタイミングでフォームモデルから送信用のデータモデルを作成
- データモデルとフォームモデルの構造は一緒である必要はない(当然、似ている方が楽ではあるが)
バリデーション
(あとで追記)