Passing formControlName into Angular component

倖福魔咒の 提交于 2020-01-15 07:47:27

问题


I have a reactive form. The setup is similar to this:

myForm: FormGroup;

    this.myForm= new FormGroup({
        name: new FormControl("", [Validators.required, Validators.maxLength(15), Validators.pattern('...')]),
        ...
    });

I use this on my form like this:

  <input
    type="text"
    formControlName="name"
  />
  <div *ngIf="name.errors?.required">
      Name is required
  </div>
  <div *ngIf="name.errors?.maxlength">
      Name must be {{ name.errors.maxlength.requiredLength }} characters        
  </div>
  <div *ngIf="name.errors?.pattern">
      Name has invalid characters.
  </div>

This is just a cut down version of my form. I have multiple input and I've had to create the error div's for each input.

So to fix this I've tried to create a component. The component is very similar to the code above:

  <input
    type="text"
    [formControlName]="formControlName"
  />
  <div *ngIf="name.errors?.required">
      Name is required
  </div>
  etc...

ts file:

@Component({
  selector: 'app-text',
  templateUrl: './text.component.html'
})
export class TextComponent  {

  @Input() formControlName: FormControl;
}

So on my form I'd like to use this component as follows:

<app-text [formControlName]="name"></app-text>

But I can't get this to work with the formControlName property.

Is this possible?

Thanks

I'm nearly there.

I've create this StackBlitz so show my progress:

Demo

Just struggling with the errors now and how to access the formControl to check for those errors


回答1:


If you want access to the formControl the best thing to use is NgControl as a DI

Reasoning:

  • NgModel
  • FormControlDirective
  • FormControlName

Are all sub-classes of NgControl so you will be doing yourself a great deal of help if you did it this way so that if down the line you change your mind about using formControl to NgControl etc... you will have already covered those bases by using NgControl

So by example it would look something like

import { Component, OnInit, Self } from '@angular/core';

import { NgControl } from '@angular/forms';

@Component({
  selector: 'app-text',
  templateUrl: './text-box.component.html',
  styleUrls: ['./text-box.component.css']
})
export class TextBoxComponent implements OnInit {

  constructor(@Self() private ngControl: NgControl) { }

  ngOnInit() {
    console.log(this.ngControl);
  }

}

Html

<app-text[formControl]="control"></app-text>

The reason we use @Self is so that the component does not look further up the injector tree to find a ngControl but only on it's element. So you can nest etc...

This is very beneficial to directives as well but so far i hope this helped!




回答2:


You need to pass the form control to the input element ,

  <input

    [value]="val"
    type="text"
    (input)="val=$event.target.value;onChange($event.target.value)"
    (blur)="onTouched()"
    [formControl]="control"

  >


  <span *ngIf="control && !control.valid && control.touched">
    <span class="error" *ngIf="control.errors['required']"> The field should not be empty</span>
    <span class="error" *ngIf="control.errors['email']"> The field should be an email 
    </span>
  </span>

Get the control in your custom component as input and show the error based on this.

import { Component, OnInit, forwardRef, Input, OnChanges } from '@angular/core';
import { FormControl, ControlValueAccessor, NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms';

@Component({
  selector: 'app-test',
  templateUrl: './test.component.html',
  styleUrls: ['./test.component.css'],
  providers: [
    { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => TestComponent), multi: true }
  ]
})
export class TestComponent implements ControlValueAccessor, OnChanges {

  constructor() { }

  propagateChange:any = () => {};

   @Input() control: FormControl;
 @Input('messageValue') _messageValue = 'whateves';  

  get messageValue() {
    return this._messageValue;
  }

  set messageValue(val) {
    console.log('set messageValue', val)
    this._messageValue = val;
    this.propagateChange(val);
  }

hi(event) {
  console.log('hi');
  console.log(event)
  this.messageValue = event;
}
  ngOnInit() {
  }

  ngOnChanges(changes) {
    console.log('changes', changes);
    this.propagateChange(this.messageValue);
  }

    writeValue(value) {
      console.log('writeValue', value);
          if (value) {
            this.messageValue = value;
      }
    }


  registerOnChange(fn) {
    console.log('onChange')
    this.propagateChange = fn;
  }

  registerOnTouched() {}

}


来源:https://stackoverflow.com/questions/56580902/passing-formcontrolname-into-angular-component

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!