最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Angular 8: formControlName inside component multiple nested levels below - Stack Overflow

programmeradmin0浏览0评论

Using this resource, I want to implement formControlName up multiple nested levels.

Angular 2 - formControlName inside component

Say the actual formGroup lives 3 component levels above a child formControlName component,

ControlValueAccessor works if the Parent component is right next to child. However multiple levels above (grandfather) form does not work.

Is there an alternative to Service, or multiple input/outputs ? Or are these the only method?

A--> Component with formGroup 
   B---> Component container
      C---> Component container
        D ---> Component with FormControlName (should pass to Component A)

Component A will collect multiple form control names from different children components similar to this,

InputText.ts

export class InputTextComponent implements  AfterViewInit, ControlValueAccessor  {
  @Input() disabled: boolean;
  @Output() saveValue = new EventEmitter();

  value: string;
  onChange: () => void;
  onTouched: () => void;

  writeValue(value: any) {
    this.value = value ? value : "";
  }

  registerOnChange(fn: any) {this.onChange = fn}

  registerOnTouched(fn: any) {this.onTouched = fn}

  setDisabledState(isDisabled) {this.disabled = isDisabled}
}

InputText.html

 <input .. />

Using this resource, I want to implement formControlName up multiple nested levels.

Angular 2 - formControlName inside component

Say the actual formGroup lives 3 component levels above a child formControlName component,

ControlValueAccessor works if the Parent component is right next to child. However multiple levels above (grandfather) form does not work.

Is there an alternative to Service, or multiple input/outputs ? Or are these the only method?

A--> Component with formGroup 
   B---> Component container
      C---> Component container
        D ---> Component with FormControlName (should pass to Component A)

Component A will collect multiple form control names from different children components similar to this,

InputText.ts

export class InputTextComponent implements  AfterViewInit, ControlValueAccessor  {
  @Input() disabled: boolean;
  @Output() saveValue = new EventEmitter();

  value: string;
  onChange: () => void;
  onTouched: () => void;

  writeValue(value: any) {
    this.value = value ? value : "";
  }

  registerOnChange(fn: any) {this.onChange = fn}

  registerOnTouched(fn: any) {this.onTouched = fn}

  setDisabledState(isDisabled) {this.disabled = isDisabled}
}

InputText.html

 <input .. />
Share Improve this question edited Nov 10, 2019 at 4:12 asked Nov 5, 2019 at 8:47 user12250118user12250118 4
  • question is unclear - can you make lives 3 levels above a child more explicit i.e. are these nested components, what is your form? You can make components that pass along whole formgroup values (or mapped values) – Andrew Allen Commented Nov 5, 2019 at 9:11
  • the <form [formGroup]="..."> lies 3 components above the formControlName in the Dom tree – user12250118 Commented Nov 5, 2019 at 16:19
  • Actually you are not obliged to use formControlName you can simply use formControl.get('path.to.prop') for the controls. – Sergey Commented Nov 9, 2019 at 22:30
  • hi @Sergey can you write in example, and I can send points? I have Angular 8 by the way;' is it good practice to do what suggested? or more deprecated practice? thanks again – user12250118 Commented Nov 10, 2019 at 2:28
Add a comment  | 

2 Answers 2

Reset to default 18 +25

You can consider four options:

1) provide ControlContainer on your component with FormControlName

d.component.ts

@Component({
  ...
  viewProviders: [
    {
      provide: ControlContainer,
      useExisting: FormGroupDirective
    }
  ]
})
export class DComponent implements OnInit {

Ng-run Example

2) create simple directive that provides ControlContainer

@Directive({
  selector: '[provideContainer]',
  providers: [
    {
      provide: ControlContainer,
      useExisting: FormGroupDirective
    }
  ]
})
export class ProvideContainerDirective {
}

then place this directive somewhere at the top of nodes hierarchy in your

d.component.html

<ng-container provideContainer>
  <input formControlName="someName">
</ng-container>

Ng-run Example

3) use FormControlDirective instead of FormControlName directive

FormControlDirective requires FormControl instance to be passed

<input [formControl]="control">

You can get this instance either though DI:

d.component.ts

export class DComponent implements OnInit {
  control;
  constructor(private parentFormGroupDir: FormGroupDirective) { }

  ngOnInit() {
    this.control = this.parentFormGroupDir.control.get('someName');
  }

Ng-run Example

or use some service that ties your components.

d.component.ts

export class DComponent implements OnInit {
  control: FormControl;

  constructor(private formService: FormService) { }

  ngOnInit() {
    this.control = this.formService.get('someName');
  }

Ng-run Example

4) pass FormGroup as Input props down to the children or get it through DI or service and then wrap your input[formControlName] with formGroup directive

d.component.html

<ng-container [formGroup]="formGroup">
 <input formControlName="..."
</ng-container>

Ng-run Example

Stackblitz

i think this is what you're looking for

follow the stackblitz example

I've created 3 components comp1 comp2 comp3

I've created the signup form in appModule and passing the formGroup to comp1 => comp2 => comp3

In comp3 I've created formControl of age property and binding it. On changing the value of age from comp3 it will get reflected in parent component, that is appComponent

Hope this helps!

Cheers!

发布评论

评论列表(0)

  1. 暂无评论