从指令中检索主机组件的 FormGroup 变量而不将其作为属性传递

Retrieving a host component's FormGroup variable from a directive without passing it as an attribute

我有以下组件:

@Component({
  templateUrl: './signup.component.html'
})
export class SignupComponent implements OnInit {

  signupForm: FormGroup; //Notice the FormGroup instance variable
  submitted = false; //Also notice the submitted variable
  ...

它使用如下自定义 feedbackClasses 指令(来自 SignupComponent 模板):

<div class="form-group" [feedbackClasses]="signupForm" [control]="'firstName'" [submitted]="submitted">

指令的定义如下:

import {Directive, ElementRef, Input, Renderer, DoCheck} from '@angular/core';
import {AbstractControl, FormGroup} from '@angular/forms';

@Directive({selector: '[feedbackClasses]'})
export class FeedbackClassesDirective implements DoCheck {

  @Input('feedbackClasses') formGroup: FormGroup;
  @Input('control') controlPath: string; //I would like to avoid passing this as an attribute
  @Input('submitted') submitted: boolean;//Same thing here

  constructor(private el: ElementRef, private renderer: Renderer) {
  }

  ngDoCheck() {
    const control: AbstractControl = this.formGroup.get(this.controlPath);
    if (control && this.submitted) {
      this.applyClasses(control.invalid);
    }
  }

  private applyClasses(inError: boolean) {
    this.renderer.setElementClass(this.el.nativeElement, 'has-success', !inError);
    this.renderer.setElementClass(this.el.nativeElement, 'has-danger', inError);
  }

}

我遇到的问题是,每次我想使用这个指令时,我都必须传入相应的FormGroup和指示表单是否已提交的boolean

有没有办法在不使用属性的情况下直接从指令中检索 FormGroupboolean?如果有怎么办?

您可以注入应用指令的组件。 为此,该指令只能应用于一种类型的组件。

@Directive({selector: '[feedbackClasses]'})
export class FeedbackClassesDirective implements DoCheck {

  @Input('feedbackClasses') formGroup: FormGroup;
  @Input('control') controlPath: string; //I would like to avoid passing this as an attribute
  @Input('submitted') submitted: boolean;//Same thing here

  constructor(private el: ElementRef, 
              private renderer: Renderer, 
              private signUpComponent: SignupComponent) {
  }

  ngOnInit() {
    console.log(this.signUpComponent.signUpForm);
    console.log(signUpComponent.submitted); // probably not set yet
  }
}

或者您可以在应该支持该指令的组件上提供共享服务并注入它

@Injectable()
export class FormStatusService {
  signupForm: FormGroup;
  submitted = false; // better use an BehaviorSubject
}
@Component({
  templateUrl: './signup.component.html':
  providers: [FormStatusService]
})
export class SignupComponent implements OnInit {

  //signupForm: FormGroup; //Notice the FormGroup instance variable
  //submitted = false; //Also notice the submitted variable

  constructor(private formStatus:FormStatusService) {
    // access shared service to read and write values
  }
  ...
}
@Directive({selector: '[feedbackClasses]'})
export class FeedbackClassesDirective implements DoCheck {

//  @Input('feedbackClasses') formGroup: FormGroup;
//  @Input('control') controlPath: string; //I would like to avoid passing this as an attribute
  // @Input('submitted') submitted: boolean;//Same thing here

  constructor(private el: ElementRef, 
              private renderer: Renderer,
              private signUpComponent: FormStatusService) {
    // access shared service to read and write values
  }
}

另见 https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service