Angular 2-当html字段具有formControlName时,在自定义指令中注入ngModel [英] Angular 2 - Inject ngModel in custom directive when html field has formControlName

查看:80
本文介绍了Angular 2-当html字段具有formControlName时,在自定义指令中注入ngModel的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have tried using a custom attribute in a field provided by a directive (class with @Directive) that I created, and this directive has NgForm injected in the constructor, but it doesn't work if the field has the formControlName attribute.

以下是演示的小插曲: http://plnkr.co/edit/gdm3Xb? p =预览

Here is the plunker of a demo: http://plnkr.co/edit/gdm3Xb?p=preview

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

The field is bound with ngModel with two-way bind, because I use the model for updating directly the fields when I want (or need) or sending data to the server. In processes like submiting the form I don't use the fields from the form itself (with controls) because the model class has several methods and isn't just an anemic model, but a rich one with several functionalities, and I don't have to care with low-level stuff like controls. The model also has all the fields (even calculated fields, if needed, not in the demo). So I have included a [(ngModel)] attribute.

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

But on the other hand, I use FormControls to use the angular validations, so I included a formControlName attribute, the validation works fine and the field behaves as expected.

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

Until now it is ok, but when I created a directive (class with @Directive) to use as an attribute (in this case, the attribute myDirective) in the field that has the formControlName attribute and the directive has a NgModel injected, I receive the following error:

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

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

In the demo I use @Optional for NgModel so as to not receive the error and the page load, but I log ngModel and it shows that it is null.

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

If I provide NgModel explicitly in the providers it doesn't show an error, but it won't be the ngModel that I want (not related to the control/field in question), so if I try to apply changes to that ngModel it won't reflect in the field.

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

If, instead, I remove the formControlName, the directive works fine (you can see in the logs where I log 'ngModel:' in one line and the object in the next: ngModel was was null before and now is an object of type NgModel). The validation also happens because of the name attribute (the formBuilder binds based on the 'name' attribute of the field). The problem is that the initial value in the model doesn't show in the field, only shows after that value changes (you can see below the field where I show the model object as JSON), and also the field doesn't stay in an invalid state even if the value in it is invalid, like when I erase the content (the border doesn't change to red and inspecting in the browser the class is ng-valid, and it is also ng-untouched, even after changing, kinda like the field and the control are not connected).

my.directive.ts

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], []] });
    }
}

main.ts

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对象已登录到我的插件中.

Just to clarify, what I want is the angular2 object NgModel related to the control, with methods like viewToModelUpdate and properties like valueAccessor. You can see the NgModel object logged in my plunker if you remove the formControlName attribute.

推荐答案

除了@Optional() arg的工作方式外,我找不到其他问题,因此我尝试寻找另一种解决方法,看看它是否可以解决问题为您服务!

I couldn't find the problem besides how the @Optional()arg works, so I tried to find another way to do it, see if it solves the problem for you!

my.directive.ts

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

这篇关于Angular 2-当html字段具有formControlName时,在自定义指令中注入ngModel的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆