ユーザーが何かのレートを入力できる入力フィールドがあります。
ユーザーが値を入力したら、四捨五入して表示し、更新された値をバッキングモデルのts
ファイルに保存します。
Angularパイプの使用は、一方向のパイプと更新された値がモデルに反映されないため、これには適していません。
双方向にするために、私は次のことをしています:
<input type="text" [ngModel]="model.rate" (ngModelChange)="model.rate=roundRate($event)" name="rate" />
roundDate
関数は次のようになります
roundRate(value) {
return Math.round(value);
}
これで、5.6、7.8、9.5などの値を入力すると、それらはすべて四捨五入され、モデルにそれぞれ表示され、6、8、および10に格納されます。これは、予想される動作です。
2.1、3.4、5.3などと入力すると問題が発生します。この場合、roundRate
関数が呼び出され、四捨五入後に値が返されます。ただし、画面に表示される値は古い値です(2.1、3.4、5.3)。
Chrome=のinput
要素を調べたところ、ng-reflect-model
プロパティは期待値(2、3、5)に更新されていました。
<input _ngcontent-c39="" name="rate" type="text" ng-reflect-name="rate" ng-reflect-model="5" class="ng-valid ng-dirty ng-touched">
誰かがここで何が起こっているのか説明してもらえますかng-reflect-model
プロパティが更新され、画面にまだ古い値が表示されるのはなぜですか?
ご協力いただきありがとうございます!
よりクリーンな実装では、_(change)
_ _@Output
_プロパティと[(ngModel)]
を使用するだけです。 roundRate
の実装により、次のように変更されます。
_import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
model = { rate: null };
roundRate() {
this.model.rate = Math.round(+this.model.rate);
}
}
_
そしてテンプレートでは:
_<input type="text" [(ngModel)]="model.rate" (change)="roundRate()" name="rate" />
_
PS:これは、入力フィールドからblur
を実行したときにのみ値を更新します
これが、参考のための Sample StackBlitz です。
ngModel
ディレクティブAPI を詳しく見てみると、ngModel
が @Input
binding であり、一部の値をmodel
変数として受け入れることがわかります。 ngModel
コントロールの初期化時に FormControl
を作成 暗黙的に。
public readonly control: FormControl = new FormControl();
model
値を更新する魔法は ngOnChanges
フック から発生するため、ビューの値をmodel
値と同期します。 ngOnChanges
フックをよく見ると、入力が検証され、他のチェックも適用されます。その後、ngModel
値の値が実際にisPropertyUpdated
メソッドを使用して変更されているかどうかが厳密にチェックされます。
ngOnChanges -ngModel
ディレクティブ
ngOnChanges(changes: SimpleChanges) {
this._checkForErrors();
if (!this._registered) this._setUpControl();
if ('isDisabled' in changes) {
this._updateDisabled(changes);
}
if (isPropertyUpdated(changes, this.viewModel)) {
this._updateValue(this.model); // helps to update
this.viewModel = this.model;
}
}
private _updateValue(value: any): void {
resolvedPromise.then(() => {
// set value will set form control
this.control.setValue(value, {emitViewToModelChange: false});
});
}
しかし、それを実現するにはAngularは変更検出サイクル中に変更を認識する必要があります。モデルを変更していないため、ngOnChangesフックはトリガーされません。
これまでに説明したのはAPI部分です。質問に戻りましょう。
以下を試してください stackblitzのスニペット 、私たちの期待はどうなるでしょう。入力値の変更時に、その値を10
自体に設定する必要があります。
<input type="text"
[ngModel]="model.rate"
(ngModelChange)="model.rate = 10"
name="rate" />
残念ながら、それはそのような方法では起こりません。最初に数値を入力すると、入力値が10
に変更され、後で入力するものはすべて数値入力に追加され続けることがわかります。ああ、なぜだろう?
元の質問に戻りましょう
<input type="text"
[ngModel]="model.rate"
(ngModelChange)="model.rate=roundRate($event)"
name="rate" />
{{model.rate}}
ngModel
は一方向バインディングとして使用されます。期待される動作は、model.rate
に割り当てられた値がinput
内に反映されていることです。 1.1と入力してみましょう。値1.1
が表示されます。次に、1.2
を入力してみてください。1.2の結果は1
になります。なぜだろう?しかし確かにmodel.rate
バインディングは正しく更新されます。同様に、4.6
、4.8
をチェックすると、結果は5となり、完全に機能します。
上記の例を分解してみましょう。1.1
を入力するとどうなりますか。
1
=> model.rateは1
になります1.
=> model.rateは1
のままです1.1
=> model.rateは1
のままです1.1
値を入力したため、最終的に1.2
または1
を入力すると、モデル値はMath.round
のままになります。これはmodel.rate
の値を更新しないため、これ以降に入力したものはすべてngModel
バインディングによって無視され、input
フィールド内に表示されます。
4.6
を確認します。4.8
は完全に機能します。どうして?それを段階的に分解する
4
=> model.rateは4
になります4.
=> model.rateは4
のままです4.6
=> model.ratebecomes5
ここで、テキストボックスに4.6
と入力すると、Math.round
の値は5
になります。 model.rate
(ngModel)の値が変更されると、input
フィールドの値が更新されます
ここで答えをもう一度読み始めます。最初に説明した技術的な側面もクリアされます。
注:回答を読んでいる間、スニペットに提供されているリンクをたどりますが、それを理解するのに役立つ場合があります。
これを機能させるには、blur
/change
のフィールドを更新してみてください。このイベントでは、fields
のフォーカスから Sid's answer
のようにフォーカスが発生します。フィールドがフォーカスされたときに一度モデルを更新しているため、うまくいきました。
しかしそれは一度だけ動作します。常に更新を維持するために、いくつかのトリックを実行できます。
this.model.rate = new String(Math.round(value));
これにより、値を丸めるたびに新しいオブジェクト参照が生成されます。
Angular変更検出戦略では、UIに変更を反映するのに役立ちます。
以下のコードを使用してください:
ステップ1:コンポーネントにChangeDetectorRef
をインポートします
import { ChangeDetectorRef} from angular/core';
ステップ2:コンストラクターにChangeDetectorRef
のインスタンスを作成します。
constructor(private ref: ChangeDetectorRef){
}
ステップ3:値を更新している場所を呼び出します。
this.ref.detectChanges();
NgModel-を使用せずに$ eventを使用してその値を取得することもできます
component.html
<table>
<tbody>
<tr>
<td colspan="2" style="width:100px;height:38px;"><input type = "text" (change)="enterDirectRowNumberResponse(data,$event.target.value)"></td></tr>
</tbody
</table>
component.ts
enterDirectRowNumberResponse(data,event){
console.log ("Inside enterDirectRowNumberResponse",event)
console.log ("data = ", data );
}