Angular 2 使用 getter 和 setter 将输入表单值与模型绑定
Angular 2 keep input form value in bind with the model using getter and setter
我想使用 getter 和设置器将输入值绑定到模型。通过这种方式,我可以防止 and/or 在写入输入值时操纵输入值。
例如,我想在输入框中输入阻止数字。所以,如果写 'abc' 一切正常,那么如果我开始写一个数字,就不会发生任何事情(对模型和输入的值)。问题是,使用以下代码,我可以在输入框中写入任何内容(但模型是正确的)。这意味着输入框的值并不真正代表我的模型。
注意:超出这个问题的原因是我想使用我的模型来验证表单,例如防止特定字符。我不想使用响应式表单,因为 我想将我的验证保留在我的模型而不是组件中。 还要注意,在真实场景中我会有一个 UserModel class 内部名称和其他字段及其验证。
@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;
}
}
}
如果您操纵 setter 中的值,这可能会导致更改检测出现问题,因此 ngModel
不会获取更改并且不会更新 <input>
要变通,您可以使用
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()
}
}
如果您将值重置为以前的值,您可能需要先传递一个人为的不同值,否则更改检测将无法检测到更改,甚至 detectChanges()
也不会更新输入。
set name(value:String) {
var oldVal = this._name;
this._name = null;
this.cdRef.detectChanges()
this._name = oldVal;
this.cdRef.detectChanges()
}
您可以使用 (ngModelChange)
和 [ngModel]
来测试更改后模型的内容。
如您在此 Plunker 中所见,模型如果无效则不会更改。
@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;
}
}
}
根据@Günter Zöchbauer 的回答,我做了一个解决方法。它不是确定的,可以更抽象,但现在还可以。
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();
}
}
在用户模型中:
....
public get name(): string {
return this.name';
}
public set name(val: string) {
if ((new RegExp(/^[a-zA-Z]*$/).test(val))) {
this.name = val;
}
}
在模板中:
<input type="text" name="userName" [ngModel]="_vm.name" (ngModelChange)="updateModel('name', $event)">
我想使用 getter 和设置器将输入值绑定到模型。通过这种方式,我可以防止 and/or 在写入输入值时操纵输入值。
例如,我想在输入框中输入阻止数字。所以,如果写 'abc' 一切正常,那么如果我开始写一个数字,就不会发生任何事情(对模型和输入的值)。问题是,使用以下代码,我可以在输入框中写入任何内容(但模型是正确的)。这意味着输入框的值并不真正代表我的模型。
注意:超出这个问题的原因是我想使用我的模型来验证表单,例如防止特定字符。我不想使用响应式表单,因为 我想将我的验证保留在我的模型而不是组件中。 还要注意,在真实场景中我会有一个 UserModel class 内部名称和其他字段及其验证。
@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;
}
}
}
如果您操纵 setter 中的值,这可能会导致更改检测出现问题,因此 ngModel
不会获取更改并且不会更新 <input>
要变通,您可以使用
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()
}
}
如果您将值重置为以前的值,您可能需要先传递一个人为的不同值,否则更改检测将无法检测到更改,甚至 detectChanges()
也不会更新输入。
set name(value:String) {
var oldVal = this._name;
this._name = null;
this.cdRef.detectChanges()
this._name = oldVal;
this.cdRef.detectChanges()
}
您可以使用 (ngModelChange)
和 [ngModel]
来测试更改后模型的内容。
如您在此 Plunker 中所见,模型如果无效则不会更改。
@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;
}
}
}
根据@Günter Zöchbauer 的回答,我做了一个解决方法。它不是确定的,可以更抽象,但现在还可以。
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();
}
}
在用户模型中:
....
public get name(): string {
return this.name';
}
public set name(val: string) {
if ((new RegExp(/^[a-zA-Z]*$/).test(val))) {
this.name = val;
}
}
在模板中:
<input type="text" name="userName" [ngModel]="_vm.name" (ngModelChange)="updateModel('name', $event)">