5

Let's say I'm writing a custom attribute directive for use on Angular2 form elements. I want to be able to use my attribute like so:

<form [formGroup]="myFormGroup">
  <input type="text" [myHighlight] formControlName="name" />
</form>

Inside my directive I have something like this:

@Directive({selector: '[myHighlight]'})
export class MyHighlightDirective {
  constructor (private el: ElementRef) {
    this.el.nativeElement.style.backgroundColor = 'yellow';
  }
};

But now let's say I want to do something on all changes to the input control. Maybe I want to randomize the color on each change.

The HostListener('onChange') event from the Angular2 guide works when the user is typing into the input box. But it doesn't get activated for setValue events that are called on the form control, even with emitEvent set to true. The Angular docs on Forms say that setValue will cause a valueChanges event to be emitted on the form control object. But I don't want to have to pass this in to the directive every time I use it, as that's clunky.

Is there any other way for the directive to get access to the original form control, given that it just has the element reference?

3 Answers 3

8

Angular DI to the rescue!

You can use the Angular Dependency Injection system to inject the FormControl attached to the host element of your directive.

@Directive({selector: '[myHighlight]'})
export class MyHighlightDirective {
  constructor (private el: ElementRef, private formControl: FormControl) {
    // have fun with formControl.valueChanges
    .......

  }
};

Why this works:

Angular registers directives into the injector of the element to which the directive is attached. So, when you ask for an instance of a particular directive, the first lookup will be on the host element first. (The same thing applies to components)

Sign up to request clarification or add additional context in comments.

12 Comments

I'm getting a No provider for FormControl! when I do that and I have FormsModule imported into my module. When I add FormControl to the providers part of my module, I get Syntax error Can't resolve all parameters for FormControl: (?, ?, ?). at SyntaxError.BaseError
Is your app divided into multiple NgModules?
Yes. I tried also importing my directive into the top AppModule, but it didn't take when I tried to use it, so instead I have a module which exports it, and then the module which applies it in the template is importing that module.
And which module is importing FormModule? Your AppModule, the module declaring MyHighlightDirective, the module containing the component using MyHighlightDirective or some other shared module that's just exporting?
MyHighlightDirective is importing it, and the module which has the input in its template is also importing it.
|
6

Inject NgControl which is type of FormControlName

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

@Directive({selector: '[myHighlight]'})
export class MyHighlightDirective {
  constructor (private el: ElementRef, private formControl: NgControl) {
    this.el.nativeElement.style.backgroundColor = 'yellow';
    ....
    //listen to validation status
    this.formControl.statusChanges.subscribe((state)=>{
       ...
    });
  }
};

Comments

0

What worked for me was

@ContentChild(NgModel)
public set model(model: NgModel) {
    ...
}

and you can access the control with model.control.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.