繁体   English   中英

Angular 2-当html字段具有formControlName时,在自定义指令中注入ngModel

[英]Angular 2 - Inject ngModel in custom directive when html field has formControlName

我尝试在我创建的指令(带有@Directive的类)提供的字段中使用自定义属性,并且此指令在构造函数中注入了NgForm,但是如果该字段具有formControlName属性,则该行不起作用。

这是一个演示的小插曲: http ://plnkr.co/edit/gdm3Xb?p=preview

情况

该字段通过双向绑定与ngModel绑定,因为我在需要(或需要)或将数据发送到服务器时使用该模型直接更新字段。 在提交表单之类的过程中,我不使用表单本身(带有控件)中的字段,因为模型类具有多种方法,不仅是贫乏的模型,而且是具有多种功能的丰富模型,并且我不必须关心诸如控件之类的低级内容。 该模型还具有所有字段(如果需要,甚至在演示中也包括计算字段)。 因此,我包含了[[ngModel)]属性。

但是另一方面,我使用FormControls来进行角度验证,因此我加入了formControlName属性,验证工作正常,并且字段的行为符合预期。

到现在为止还可以,但是当我在具有formControlName属性的字段中创建了一个指令(带有@Directive的类)用作属性(在本例中为myDirective属性)并且该指令注入了NgModel时,我收到了出现以下错误:

Error: Uncaught (in promise): EXCEPTION: Error in ./AppComponent class AppComponent - inline template:4:3
ORIGINAL EXCEPTION: No provider for NgModel!

在演示中,我对NgModel使用@Optional,以便不接收错误和页面加载,但是我登录ngModel,它显示为空。

如果我在提供程序中明确提供NgModel,则不会显示错误,但不会是我想要的ngModel(与所涉及的控件/字段无关),因此,如果我尝试将更改应用于该ngModel不会反映在现场。

如果我改为删除formControlName,则该指令可以正常工作(您可以在日志中看到我在一行中记录了“ ngModel:”,而在下一行中记录了该对象:ngModel之前为null,现在是NgModel类型的对象)。 由于name属性(formBuilder基于字段的“ name”属性进行绑定),因此也会进行验证。 问题在于模型中的初始值不会显示在字段中,仅在值更改后才会显示(您可以在字段下方看到将模型对象显示为JSON的字段),并且该字段也不会停留在无效状态,即使其中的值无效,例如当我擦除内容时(边框不会变为红色并在浏览器中检查该类是否为ng有效,即使更改后该类也为ng不变) ,有点像字段和控件未连接)。


档案

我的指令

import { Directive, Optional } from '@angular/core';
import { NgModel } from '@angular/forms';

@Directive({
    selector: '[myDirective]'
})
export class MyDirective {
    constructor(@Optional() ngModel: NgModel) {
        console.log('ngModel:');
        console.log(ngModel);       
    }
}

app.component.ts

import { Component } from '@angular/core';
import { REACTIVE_FORM_DIRECTIVES, FormBuilder, FormGroup, Validators } from '@angular/forms';

import { MyDirective } from './my.directive';

@Component({
    selector: 'my-app',
    template: `
        <h1>My Angular 2 App</h1>

        <form [formGroup]="formGroup" [class.error]="!myInput.valid && myInput.touched">
            <input 
                name="myInput" 
                type="text" 
                [(ngModel)]="model.myInput" 
                formControlName="myInput" 
                #myInput
                myDirective="123"
            >
            <div *ngIf="formGroup.controls.myInput.dirty && !formGroup.controls.myInput.valid">
                myInput is required
            </div>
        </form>
    `,
    directives: [REACTIVE_FORM_DIRECTIVES, MyDirective]
})
export class AppComponent {
    public model: { myInput: number } = { myInput: 456 };
    public formGroup: FormGroup;

    constructor(private formBuilder: FormBuilder) { }

    ngOnInit() {
        this.formGroup = this.formBuilder.group({ myInput: ['', [Validators.required], []] });
    }
}

主要

import { bootstrap } from '@angular/platform-browser-dynamic';
import { disableDeprecatedForms, provideForms } from '@angular/forms';
import { AppComponent } from './app.component';

bootstrap(AppComponent, [
    disableDeprecatedForms(),
    provideForms()
]);

TL; DR

我想知道是否有一种方法可以使指令接收NgModel,但与此同时,我希望表单也可以按照现在的方式工作(使用双向数据绑定,因此我可以使用模型对象,而且还可以使用FormBuilder定义字段的验证器)。

更新

为了明确起见,我想要的是与控件相关的angular2对象NgModel,它具有viewToModelUpdate之类的方法以及valueAccessor之类的属性。 如果删除formControlName属性,则可以看到在我的插件中记录的NgModel对象。

除了@Optional() arg的工作方式之外,我找不到任何问题,因此我试图找到另一种方法来解决它,看看是否能为您解决问题!


档案

我的指令

import { Directive, Input,Optional , HostListener} from '@angular/core';
import { NgModel } from '@angular/forms';

@Directive({
    selector: '[myDirective]'
})
export class MyDirective {
    @Input('myDirective') ngModel:NgModel;
    constructor() {
    }
    /**Added to check if the Input is being updated**/
    @HostListener('mouseenter') onMouseEnter() {
      console.log('ngModel:');
      console.log(this.ngModel)
    }
    /**Inputs are only received OnInit**/
    ngOnInit()
    {
        console.log('ngModel:');
        console.log(this.ngModel)
    }
}

app.component.ts

import { Component } from '@angular/core';
import { REACTIVE_FORM_DIRECTIVES, FormBuilder, FormGroup, Validators } from '@angular/forms';

import { MyDirective } from './my.directive';

@Component({
    selector: 'my-app',
    template: `
        <h1>My Angular 2 App</h1>

        <form [formGroup]="formGroup">
            <input 
                name="myInput" 
                type="text" 
                [(ngModel)]="model.myInput" 
                formControlName="myInput"
                [myDirective]="model"
                #myInput
            >
            <div *ngIf="formGroup.controls.myInput.dirty && !formGroup.controls.myInput.valid">
                myInput is required
            </div>

            <br><br>

            {{ model | json }}
        </form>
    `,
    directives: [REACTIVE_FORM_DIRECTIVES, MyDirective]
})
export class AppComponent {
    public model: { myInput: number } = { myInput: 456 };
    public formGroup: FormGroup;

    constructor(private formBuilder: FormBuilder) { }

    ngOnInit() {
        this.formGroup = this.formBuilder.group({ myInput: ['789', [Validators.required], []] });
    }
}

工作的朋克: http ://plnkr.co/edit/nYtsXH?p=preview

暂无
暂无

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

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