Angular2 自定义组件 - 标记为原始且未受影响

Angular2 Custom Component - mark as pristine and untouched

我在 Angular 2.1 中有一个模板驱动的表单,其中包含许多标准控件(<input>, <select> 等)和一个自定义控件,它本身包含多个输入元素。

我已经在自定义控件上实现了 ControlValueAccessor,它正在将它的 changed/touched/valid 值正确传播到父窗体。

但是 .. 在父表单上我有一个保存按钮,保存后我想在该按钮上清除 dirty/touched 状态(因为这会影响应用的 css),如下所示:

save(myForm: NgForm) {

    myForm.form.markAsPristine();
    myForm.form.markAsUntouched();

}

这对于顶级父表单中的所有元素和自定义控件本身都工作正常但是自定义控件中的<input>字段仍然被标记为touched/dirty(并且接收到预先保存的样式)。

有没有一种方法可以在 dirty/touched 状态更改时通知自定义控件,以便它可以清除其子 <input> 元素以进行匹配?似乎如果 <input> 元素在自定义控件中,则它们不会通过调用父表单上的 markAsPristine/Untouched 来更新。

谢谢!

尝试像这样添加controls['nameOfControl']

 myForm.form.controls['nameOfControl'].markAsPristine();

以上代码仅适用于表单控件。

以下似乎是一个很好的解决方法:

  active = true;
  newModel() {
    this.model = new yourModel(2, '',true, '');
    this.active = false;
    setTimeout(() => this.active = true, 0);
  }

使用新模型重置表单并恢复 'pristine' class 状态。 通过切换 'active' 标志将导致表单通过 NgIf 在勾选中变为 removed/re-added。是的,这是一个小的变通办法,直到他们可以解决 :)

希望对您有所帮助

使用活动标志的解决方法可以解决问题,但我还找到了另一种方法。

在 parent 表单上,我可以访问我的自定义 child 组件作为 ViewChild。

即 parent 形式:

@ViewChild(CustomChildComponent) child1: CustomChildComponent;

然后当我保存在parent形式时,直接调用那个child。

save(myForm: NgForm) {

   // clear anything at the parent form level
   myForm.form.markAsPristine();
   myForm.form.markAsUntouched();

   // tell the custom component to do the same
   this.child1.markAsPristineAndUntouched();
}

我在 CustomChildComponent 中定义的位置 ..

// get the input controls in the the child that we want to clear 
@ViewChild('surname') surnameField: NgModel;

markAsPristineAndUntouched() { 

   this.surnameField.control.markAsPristine();
   this.surnameField.control.markAsUntouched();
   // .. clear other controls .. 
}

markAsPristine() 可以影响控件本身,并且可能 它的所有直接祖先 控件(即 parents、grandparents、曾祖parents)

markAsPristine() 接受一个 opts 参数; markAsPristine(opts: { onlySelf?: boolean; } = {})。当 onlySelf 值为 false(这是默认值)时,控件及其所有直接祖先都被标记为原始。如果 onlySelftrue;只有控件本身被标记为原始。

在我的例子中,我想将所有 descendant 控件(即 child、grandchild 等)标记为 pristine/untouched。 我可以做到这一点 FormGroup.reset() ; reset() 有能力影响 后代:

Resets the FormGroup, marks all descendants are marked pristine and untouched, and the value of all descendants to null.

因此,使用 OP 的代码,我可以使用它已有的值重置表单:

myForm.form.reset(myForm.form.getRawValue(), {emitEvent: false})

注意我是如何避免某些副作用的:

  • 我使用表格的当前值,所以我不更改当前值
  • 使用getRawValue(),而不是value,来获取禁用控件的值
  • emitEvent;这意味着 不会触发任何值更改

我的解决办法是观察主机变化

我有一个实现 controlValueAccessor 接口的组件。我用这个组件做成一个表单,用 ngModel.

当 Angular 表单 api 更改宿主元素 class 属性时将其设置为 dirty、prinstine、touched 等...我设置 mi 组件 class attibute到主机 class 属性。

构造函数(私有主机元素:ElementRef){

this.changes = new MutationObserver((mutations: MutationRecord[]) => {
  mutations.forEach(
    (mutation: MutationRecord) => (this.controlClasses = mutation.target['className']),
  );
});

this.changes.observe(this.hostElement.nativeElement, {
  attributes: true,
  attributeFilter: ['class'],
});

}

在模板上

 <span class="ui-float-label">
  <input
    #inputElement
    [disabled]="disabled"
    [type]="type"
    [required]="required"
    [(ngModel)]="value"
    (ngModelChange)="handleValueChange($event)"
    (blur)="onBlur()"
    [pattern]="pattern"
    [type]="type"
    [size]="size"
    pInputText
    class="p-inputtext"
    [ngClass]="controlClasses"
  />

  <label *ngIf="!required" for="float-input">{{ placeholder }}</label>
  <label *ngIf="required" for="float-input">{{ placeholder }}*</label>
</span>

现在每次主机更改他的 classes 时,更改都会传播到子控件。