简体   繁体   English

Angular 2使用getter和setter将输入表单值与模型绑定

[英]Angular 2 keep input form value in bind with the model using getter and setter

I would like to bind an input value to the model using getter and setters. 我想使用getter和setter将输入值绑定到模型。 In this way i can prevent and/or manipulate the input's value while writing inside it. 这样,我可以在内部进行输入时防止和/或操纵输入的值。

For example i want the prevent numbers inside an input box. 例如,我要在输入框中输入阻止编号。 So, if write 'abc' all is ok, then if I start writing a number nothing should happen (to the model and to the input's value). 因此,如果全部写'abc'没问题,那么如果我开始写一个数字,则什么也不会发生(对于模型和输入值)。 The issue is that with the following code i'm able to write anything inside the input box (but the model it's correct). 问题在于,使用以下代码,我可以在输入框内编写任何内容(但模型是正确的)。 This means that the input box value is not really representing my model. 这意味着输入框值不能真正代表我的模型。

NOTE: The reason beyond this questions is that I want to use my models to validate forms, preventing for example specific characters. 注意:超出此问题的原因是,我想使用我的模型来验证表单,例如防止使用特定字符。 I would like to not use reactive forms as i want to keep my validations inside my models not components. 我不想使用反应形式,因为我想将验证保留在模型中而不是组件中。 Also note that in a real scenario i would have a UserModel class with inside name and other fields with their validations. 还要注意,在实际情况下,我将拥有一个带有内部名称的UserModel类以及带有其验证的其他字段。

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2><input type="text" [(ngModel)]="name"> {{name}}</h2>
    </div>
  `,
})
export class App {
  _name:string = 'ss';
  constructor() {
  }

  // In real scenario those 2 methods are in a separate class UserModel
  get name() {
    return this._name;
  }

  set name() {
    if ((new RegExp(/^[a-zA-Z]*$/).test(val))) {
        this._name = val;
    }
  }
}

If you manipulate the value in the setter, this can cause issues with change detection, so that ngModel doesn't pick up the changes and doesn't update the <input> 如果您在设置器中操作该值,则可能会导致更改检测出现问题,因此ngModel不会获取更改,也不会更新<input>

To work around you can use 要变通,您可以使用

export class App {

  _name:string = 'ss';

  constructor(private cdRef:ChangeDetectorRef) {}

  get name() {
    return this._name;
  }

  set name(value:String) {
    this._name = value + 'x';
    this.cdRef.detectChanges()
  }
}

if you reset the value to the previous value, you might need to pass an artificial different value first, otherwise change detection won't detect a change and even detectChanges() won't update the input. 如果将值重置为先前的值,则可能需要先传递一个人工的不同值,否则更改检测将不会检测到更改,甚至detectChanges()也不会更新输入。

  set name(value:String) {
    var oldVal = this._name;
    this._name = null;
    this.cdRef.detectChanges()
    this._name = oldVal;
    this.cdRef.detectChanges()
  }

Based on @Günter Zöchbauer answer i made a workaround. 基于@GünterZöchbauer的答案,我提出了一种解决方法。 It's not definitive and could be more abstract, but for now it's ok. 它不是确定的,可以更抽象,但是现在还可以。

export class App implements OnInit {
    @Input() userModel: UserModel = null;
    public _vm;

    constructor(private _changeDetectionRef: ChangeDetectorRef) {
    }

    /**
     * Initalize view model, it's important to keep names specular
     */
    ngOnInit() {
        this._vm = {
            name: this.userModel.name,
            surname: this.userModel.surname,
        };
    }

    /**
     * Helper for avoid detectchanges inside the modal, and reduce boilerplate. We could also ad an interface/type of the possibile field value, ie type fieldT= 'name' | 'surname';
     * @param field
     * @param val
     */
    protected updateModel(field, val: string): void {
        this._vm[field] = null;
        this._changeDetectionRef.detectChanges();
        this.userModel[field] = val;
        this._vm[field] = this.userModel[field];
        this._changeDetectionRef.detectChanges();
    }
}

In userModel: 在userModel中:

....

    public get name(): string {
        return this.name';
    }

    public set name(val: string) {
        if ((new RegExp(/^[a-zA-Z]*$/).test(val))) {
            this.name = val;
        }
    }

In template: 在模板中:

<input type="text"  name="userName"  [ngModel]="_vm.name" (ngModelChange)="updateModel('name', $event)">

You can use (ngModelChange) and [ngModel] to test the content of your model upon change. 您可以使用(ngModelChange)[ngModel]在更改时测试模型的内容。

As you can see in this Plunker the model wont change if it is not valid. 如您在此柱塞中所见 ,如果模型无效,则模型不会更改。

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2><input #input type="text" [ngModel]="name" (ngModelChange)='valid(input.value)'> {{name}}</h2>
    </div>
  `,
})
export class App {
  name:string = 'ss';
  constructor() {
  }

  valid(value){
    if(value){ //<--- Your test here
      this.name = value;
    }
  }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM