Angular2 - 表单错误行为中的自定义指令
Angular2 - Custom directives inside form misbehavior
我在使用模板中带有 <input ...>
标签的自定义指令时遇到问题,当它们位于 angular 表单中时。
如果您在表单中声明输入,编辑输入字段将改变表单的属性,如预期的原始、触摸、有效等。
如果您在表单中声明自定义指令,比如 <ac2-string-input ...></ac2-string-input>
并且它的模板包含一个输入,那么如果您编辑此输入的字段,它 将不会 改变表单的 属性.
这是为什么?那是一个错误吗?有什么解决方法吗?
下面有一个例子:
我们可以有一个表单组件,在app/form.component.ts
import { Component } from '@angular/core'
import { InputComponent } from './input.component'
@Component({
selector: 'ac2-form',
templateUrl: '<build path>/templates/form/form.html',
directives: [InputComponent]
})
export class FormComponent {
item: Object = {
attr1: 'blah',
attr2: 'another blah'
}
constructor(){}
submit(){ console.log(this.item) }
}
使用模板 templates/form/form.html
<form #f="ngForm" (ngSubmit)="submit()">
<input type="text" name="attr1" [(ngModel)]="item.attr1"/>
<ac2-string-input [obj]="item"></ac2-string-input>
<button type="submit">Submit</button>
</form>
<div>
Pristine? {{f.form.pristine}}
</div>
和ac2-string-input指令定义在app/form/input.component.ts
import { Component, Input } from '@angular/core'
@Component({
selector: 'ac2-string-input',
templateUrl: '<build path>/templates/form/input.html'
})
export class InputComponent {
@Input() obj: Object;
constructor(){}
}
使用模板 templates/form/input.html
<input type="text" name="attr2" [(ngModel)]="obj.attr2"/>
如果我们加载表单,将有两个文本字段,表单将是 "Pristine"
如果我们编辑 "attr2" 字段,表单将继续保持原始状态,就好像该字段未绑定到表单一样!
如果我们编辑 "attr1" 字段,表单将不会像预期的那样是原始的。
内部 input
可能无法识别为表单的一部分,因为 ac2-string-input
不是标准的 HTML 输入。
您可以通过输出表单的控件或值并查找 attr2
属性 来验证这一点。如果它不存在,Angular
甚至不知道它,因此更改该输入不会影响表单的 pristine
状态。
为了使集成更容易,请考虑使用属性指令而不是组件。这将改变:
<ac2-string-input [obj]="item"></ac2-string-input>
到
<input type="text" [ac2StringInput]="item"/>
指令类似于:
@Directive({
selector: '[ac2StringInput]',
host: {
// onKeyup gets executed whenever the input receives input
'(keyup)':'onKeyup($event)'
}
})
export class InputComponent {
constructor() {}
/**
* ac2StringInput to the outside refers to obj within this directive
*/
@Input('ac2StringInput') obj:Object;
/**Handle keyup*/
onKeyup($event){}
}
如果您想更清楚地了解指令之外发生的事情,您甚至可以将整个 form
作为输入传递给指令。
我在 Angular 2 的 github 中打开了一个 issue。
事实证明,如果我们想让我们的组件被识别为表单控件,我们需要实现ControlValueAccessor
接口并将ngModel放在顶层。
THIS Plunkr 展示了如何做到这一点。
感谢 kara 为我解决了这个问题。
我在使用模板中带有 <input ...>
标签的自定义指令时遇到问题,当它们位于 angular 表单中时。
如果您在表单中声明输入,编辑输入字段将改变表单的属性,如预期的原始、触摸、有效等。
如果您在表单中声明自定义指令,比如 <ac2-string-input ...></ac2-string-input>
并且它的模板包含一个输入,那么如果您编辑此输入的字段,它 将不会 改变表单的 属性.
这是为什么?那是一个错误吗?有什么解决方法吗?
下面有一个例子:
我们可以有一个表单组件,在app/form.component.ts
import { Component } from '@angular/core'
import { InputComponent } from './input.component'
@Component({
selector: 'ac2-form',
templateUrl: '<build path>/templates/form/form.html',
directives: [InputComponent]
})
export class FormComponent {
item: Object = {
attr1: 'blah',
attr2: 'another blah'
}
constructor(){}
submit(){ console.log(this.item) }
}
使用模板 templates/form/form.html
<form #f="ngForm" (ngSubmit)="submit()">
<input type="text" name="attr1" [(ngModel)]="item.attr1"/>
<ac2-string-input [obj]="item"></ac2-string-input>
<button type="submit">Submit</button>
</form>
<div>
Pristine? {{f.form.pristine}}
</div>
和ac2-string-input指令定义在app/form/input.component.ts
import { Component, Input } from '@angular/core'
@Component({
selector: 'ac2-string-input',
templateUrl: '<build path>/templates/form/input.html'
})
export class InputComponent {
@Input() obj: Object;
constructor(){}
}
使用模板 templates/form/input.html
<input type="text" name="attr2" [(ngModel)]="obj.attr2"/>
如果我们加载表单,将有两个文本字段,表单将是 "Pristine"
如果我们编辑 "attr2" 字段,表单将继续保持原始状态,就好像该字段未绑定到表单一样!
如果我们编辑 "attr1" 字段,表单将不会像预期的那样是原始的。
内部 input
可能无法识别为表单的一部分,因为 ac2-string-input
不是标准的 HTML 输入。
您可以通过输出表单的控件或值并查找 attr2
属性 来验证这一点。如果它不存在,Angular
甚至不知道它,因此更改该输入不会影响表单的 pristine
状态。
为了使集成更容易,请考虑使用属性指令而不是组件。这将改变:
<ac2-string-input [obj]="item"></ac2-string-input>
到
<input type="text" [ac2StringInput]="item"/>
指令类似于:
@Directive({
selector: '[ac2StringInput]',
host: {
// onKeyup gets executed whenever the input receives input
'(keyup)':'onKeyup($event)'
}
})
export class InputComponent {
constructor() {}
/**
* ac2StringInput to the outside refers to obj within this directive
*/
@Input('ac2StringInput') obj:Object;
/**Handle keyup*/
onKeyup($event){}
}
如果您想更清楚地了解指令之外发生的事情,您甚至可以将整个 form
作为输入传递给指令。
我在 Angular 2 的 github 中打开了一个 issue。
事实证明,如果我们想让我们的组件被识别为表单控件,我们需要实现ControlValueAccessor
接口并将ngModel放在顶层。
THIS Plunkr 展示了如何做到这一点。
感谢 kara 为我解决了这个问题。