ngModel 自定义 ValuesAccessor

Posted

技术标签:

【中文标题】ngModel 自定义 ValuesAccessor【英文标题】:ngModel custom ValuesAccessor 【发布时间】:2016-05-01 23:01:32 【问题描述】:

关于 ngModel 和 DI 的高级问题。

正如我在这里看到的 = https://github.com/angular/angular/blob/2.0.0-beta.1/modules/angular2/src/common/forms/directives/ng_model.ts#L68 ngModel 等待提供者来自 NG_VALUE_ACCESSOR OpaqueToken。这意味着如果我想创建应该支持 ngModel 绑定的自定义组件,我应该将我的 ValueAccessor 实现传递给 DI。所以我有两个问题。

1) 我该怎么做?

2) <input> 元素的默认 ValueAccessor 是什么?如何让它继续工作并将我的仅用于自定义组件?

顺便说一句,我在这里看到:https://github.com/angular/angular/blob/2.0.0-beta.1/modules/angular2/src/common/forms/directives/shared.ts#L102 defaultValueAccessor 是最后一个。所以这意味着如果我通过 DI 系统全局传递我的 ValueAccessor,而不是默认的永远不会返回。

【问题讨论】:

如何扩展默认功能或将其包装在您的自定义功能中,这样即使您一直使用它,您也可以分叉代码来决定运行这两个功能中的哪一个?跨度> 【参考方案1】:

您可以在相应指令的providers(不推荐使用bindings)属性中注册这样的自定义ControlValueAccessor

const CUSTOM_VALUE_ACCESSOR = CONST_EXPR(new Provider(
  NG_VALUE_ACCESSOR,
  useExisting: forwardRef(() => TagsValueAccessor), multi: true));

@Directive(
  selector: 'tags',
  host: '(labelsChange)': 'onChange($event)',
  providers: [CUSTOM_VALUE_ACCESSOR]
)
export class TagsValueAccessor implements ControlValueAccessor 
  (...)

那么当你将ngModel 和/或ngFormControl 用于带有选择器tags 的组件时,将自动选择此访问器:

@Component(
  (...)
  directives: [ TagsComponent, TagsValueAccessor ],
  template: `
    <tags [(ngModel)]="company.labels" 
          [ngFormControl]="companyForm.controls.labels"></tags>
  `
  )
  export class DetailsComponent 
    (...)
  

此问题中提供了完整示例:Angular 2 custom form input。

希望对你有帮助 蒂埃里

【讨论】:

【参考方案2】:

当您可以使用内部 ngModel 时,为什么要创建新的值访问器。

这回答了@Maksim Fomim 的第二个问题

模板:

<div class="form-group" [ngClass]="'has-error' : hasError">
    <div><label>label</label></div>
    <input type="text" [placeholder]="placeholder" ngModel [ngClass]="invalid: (invalid | async)" [id]="identifier"        name="name-input" />    
</div>

组件:

export class MyInputComponent 
    @ViewChild(NgModel) innerNgModel: NgModel;

    constructor(ngModel: NgModel) 
        //First set the valueAccessor of the outerNgModel
        this.outerNgModel.valueAccessor = this.innerNgModel.valueAccessor;

        //Set the innerNgModel to the outerNgModel
        //This will copy all properties like validators, change-events etc.
        this.innerNgModel = this.outerNgModel;
    

用作:

<my-input class="col-sm-6" label="First Name" name="firstname" 
    [(ngModel)]="user.name" required 
    minlength="5" maxlength="20"></my-input>

【讨论】:

以上是关于ngModel 自定义 ValuesAccessor的主要内容,如果未能解决你的问题,请参考以下文章

ngModel、自定义管道和模式的单元测试错误[重复]

自定义指令

在 Angular2 ngModel 值未在自定义指令的 onBlur 事件上更新

如何使用角度验证自定义验证模式中的文本

自定义组件之间的双向绑定

当被 JavaScript 更改时,Angular 无法通过 [(ngModel)] 获取输入值