输入未更新视图时对NgModel的更改

时间:2018-03-15 13:18:58

标签: angular

我的html上有一个输入字段,我需要限制它的值。

我正在尝试这样做:

HTML:

<div *ngFor="let option of options">
    <input type="text" [ngModel]="option.value" (change)="onChangeValue($event.target.value, option)">
</div>

打字稿:

onChangeValue(valueString: string, option: OptionViewModel) {
    var value: number = parseInt(valueString);

    // Check some conditions. Simplified code just for example
    if (option.value != value && value > 5) {
        value = 5;
    }

    option.value = value;
}

OptionViewModel:

export class OptionViewModel {
    public optionId: number;
    public description: string;
    public pollId: number;
    public value?: number;
}

我尝试使用双向绑定,但我的代码依赖于option.value的先前值,并且在进入函数之前使用双向绑定更改变量。

问题是,有时输入字段没有更新。 看起来我刚刚第一次工作时需要更改值,所以例如,如果输入6字段正确地更改为5,但是如果我添加0(使其为50),则它不会更正为5.

我对代码进行了重新编译,它正在运行该函数并更改option.value,甚至使用Augury来检查对象是否显示正确的值。

5 个答案:

答案 0 :(得分:2)

您尝试更改ng模型双向绑定,就像那样

    <div *ngFor="let option of options">
        <input type="text" [(ngModel)]="option.value"  #ctrl="ngModel"
 (change)="onChangeValue($event.target.value, option)">
    </div>

答案 1 :(得分:2)

在第二次编辑时,输入元素的内容未更新,因为Angular未检测到任何更改(option.value为5,且仍为5)。以下是强制刷新元素的两种方法。

方法1 - 替换数组中的选项

您可以通过使用克隆副本替换数组中的选项来强制更新字段,如 this stackblitz

中所示
<div *ngFor="let option of options; let i=index">
  <input [ngModel]="option.value" (change)="onChangeValue($event.target.value, i)" type="text" >
</div>
onChangeValue(valueString: string, index: number) {
  var value: number = parseInt(valueString);
  if (value > 5) {
    value = 5;
  }
  this.options[index] = this.options[index].cloneWithValue(value);
}

export class OptionViewModel {
  public optionId: number;
  public description: string;
  public pollId: number;
  public value?: number;

  public cloneWithValue(value: number): OptionViewModel {
    let dest = new OptionViewModel();
    dest.optionId = this.optionId;
    dest.description = this.description;
    dest.pollId = this.pollId;
    dest.value = value;
    return dest;
  }
}

方法2 - 在trackBy函数中使用其他字段

另一种解决方案是向OptionViewModel添加其他字段(例如lastModified),并在trackBy指令的ngFor方法中使用它(请参阅{{ 3}}):

<div *ngFor="let option of options; trackBy: trackByFn">
  <input [ngModel]="option.value" (change)="onChangeValue($event.target.value, option)" type="text">
</div>
onChangeValue(valueString: string, option: OptionViewModel) {
  var value: number = parseInt(valueString);
  if (value > 5) {
    value = 5;
  }
  option.value = value;
  option.lastModified = Date.now();
}

trackByFn(index: number, option: OptionViewModel) {
  return `${index}___${option.lastModified}`;
}
export class OptionViewModel {
  public optionId: number;
  public description: string;
  public pollId: number;
  public value?: number;
  public lastModified: number = 0;
}

答案 2 :(得分:0)

您也可以尝试创建一个简单的observable来为您检查信息。

import { Component, ViewChild, ElementRef, OnInit } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/fromEvent';
import 'rxjs/add/operator/map';

@Component({
  selector: 'my-app',
  template: `<input #inputName type="text" />`,
})
export class AppComponent implements OnInit {
  value: string = '';
  @ViewChild('inputName') inputName: ElementRef;

  ngOnInit() {
    const input = this.inputName.nativeElement as HTMLInputElement;
    Observable.fromEvent(input, 'input')
      .map((evt: Event) => evt.target as HTMLInputElement)
      .subscribe(target => target.value = Number(target.value) > 5 ? '5' : target.value);
  }
}

答案 3 :(得分:0)

对我来说,最简单的解决方案是使用ChangeDetectorRef。更改检测树将收集所有视图并更新所有组件的值

  1. 在构造器中使ChangeDetectorRef的变量类型如下所示:-

     constructor(private changeDet:ChangeDetectorRef) { }
    
  2. 现在只需在设置/更新值后调用 changeDet.detectChanges()

     onChangeValue(valueString: string, option: OptionViewModel) {
     var value: number = parseInt(valueString);
    
     // Check some conditions. Simplified code just for example
     if (option.value != value && value > 5) {
         value = 5;
     }
    
     option.value = value;
     this.changeDet.detectChanges();//Detects changes and updates value
    }
    

答案 4 :(得分:0)

找到了一个更简单的解决方法。只需使用 (keyup) 而不是 (change)

<input class="editable-field-input" type="number" value="editableFieldValue" [(ngModel)]="editableFieldValue" (keyup)="editableFieldValueChanged()" />

我没有将事件作为参数传递,因为我已经让 ngModel 更新了我的变量。

editableFieldValueChanged() {
  if (this.editableFieldValue < -100) {
    this.editableFieldValue = -100;
  }
  if (this.editableFieldValue > 100) {
    this.editableFieldValue = 100;
  }
}

TLDR 版本是,Angular 认为这与在下拉列表中一遍又一遍地选择相同的选项相同,因为以前的值和当前值是相同的,因此它找不到更新 DOM 元素的理由。

我相信这种方法有效,因为 (keyup) 与其他事件相比具有不同的执行顺序。我会把解释留给比我知识渊博的人。