web-dev-qa-db-ja.com

オブザーバブルを使用するための拡張Angular 2 ngModelディレクティブ

Angular 2 ngModelディレクティブは、次のような変数と関数で動作します

<input [ngModel]="myVar" (ngModelChange)="myFunc($event)" />

変数と関数の代わりに、代わりにBehaviorSubjectsを使用したいと思います

<input [ngModel]="mySubject | async" (ngModelChange)="mySubject.next($event)" />

テンプレートの繰り返しを減らすためにngModelを拡張したり、ある種のマクロを使用したりする安全な方法はありますか?

<input [myNewNgModel]="mySubject" />

21
nwarp

なぜリアクティブフォームを使用しないのかはわかりませんが、これは楽しいパズルでした。モデル値をBehaviorSubjectの値に変更するディレクティブを作成しました。また、変更を加えると、BehaviorSubject.nextが呼び出されます。

使用法は次のようになります

<input type="text" [ngModel]="ngModelValue" appRxModel> 

これが stackblitz です。お楽しみください

1
realappie

フォームの各入力フィールドにオブザーバブルを作成しますか?私が使用するパターンは、フォーム全体のモデルに対して1つのオブザーバブルを用意し、それをバインドできるビュー変数用にそれを複製してから、フォームの送信ハンドラーに新しいモデルをサービスにプッシュするというものです。

user$ = this.userService.user$;

save(user: User) {
  this.userService.save(user);
}

とビューで

<form *ngIf="user$ | async | clone as user" #userForm="ngForm" (submit)="userForm.form.valid && save(user)">
  <label>
    Firstname
    <input name="firstname" [(ngModel)]="user.firstname" required>
  </label>
  <label>
    Lastname
    <input name="lastname" [(ngModel)]="user.lastname" required>
  </label>
  <button>Save</button>
</form>

クローンパイプはこんな感じ

export const clone = (obj: any) =>
  Array.isArray(obj)
    ? obj.map(item => clone(item))
    : obj instanceof Date
    ? new Date(obj.getTime())
    : obj && typeof obj === 'object'
    ? Object.getOwnPropertyNames(obj).reduce((o, prop) => {
        o[prop] = clone(obj[prop]);
        return o;
      }, {})
    : obj;

import { Pipe, PipeTransform } from '@angular/core';

import { clone } from './clone';

@Pipe({
  name: 'clone'
})
export class ClonePipe implements PipeTransform {

  transform(value: any): any {
    return clone(value);
  }
}

私は、この状態管理ライブラリーを使用して、このパターンについてここで説明しました。 https://medium.com/@adrianbrand/angular-state-management-with-rxcache-468a865fc3fb

0
Adrian Brand

私は@Adbelに同様のアプローチを思いつきました。これの内面的な意味については不明ですが、フィードバックがあると素晴らしいでしょう。 Stackblizコード

Your.component.ts

export class AppComponent  {
  email = new BehaviorSubject("UnwrappedMe ????");

  emailHandler(input) {
    this.email.next(input);
  }
}

Your.component.html

 <form class="mx-3">
     <input [ngModel]="email | async" 
            (ngModelChange)="emailHandler($event)" 
            name="email" type="email" 
            id="email" placeholder="Enter email">
 </form>

 <p class="mx-3"> {{ email | async }} </p>

入力値への参照を取得する必要があり、2番目のサブスクリプションを作成したくない場合の小さなバリエーション(テンプレート変数を使用)。

Your.component.html

 <form class="mx-3">
     <input [ngModel]="email | async" #emailref
            (ngModelChange)="emailHandler($event)" 
            name="email" type="email" 
            id="email" placeholder="Enter email">
 </form>

 <p class="mx-3"> {{ emailref.value }} </p>
0
Luillyfe