schaenk
schaenk

Reputation: 682

Extending Angular component with directive

I wrote a directive which is adding a HostListener (in this case "focus") on any component. The directive should call a method on it's host component whenever the element is on focus.

<my-component myDirective>
    <h3>Hello World</h3>
</my-component>

<my-other-component myDirective>
    <button>Hello</button>
</my-other-component>

The HostListener inside myDirective

@HostListener('focus')
onFocus() {
    this.myService.myStream$
        .pipe(first())
        .subscribe((value => {
            this.myHostComponent.doSomeMagic(value);
        }))
}

Since it should work on every component i prefer to only implement the doSomeMagic() method in the components and letting the myDirective doing the work with the HostListener and the observable.

Is there a way to call a method on the directives host without knowing which component it actualy is?

Upvotes: 1

Views: 3352

Answers (2)

Roberto Zvjerković
Roberto Zvjerković

Reputation: 10147

You can do it with an injected component:

Something like this should work, directive.ts:

constructor(private myHostComponent: MyComponent) {}

...

this.myHostComponent.doSomeMagic(value);

You will have to know the type of component tho.

I believe it could work if you would make and abstract component from which all your doSomeMagic() components will extend:

constructor(private myHostComponent: MyAbstractComponent) {}

class MyAbstractComponent() { abstract doSomeMagic(); }

I'm not sure about the abstract part, you will need to check if it works.

Edit:

You can also pass the reference to the component/element via directive input. Here is a quick StackBlitz:

https://stackblitz.com/edit/angular-playground-anhhhc?file=app/directive.ts

Upvotes: 0

Neter
Neter

Reputation: 108

I would do it with @Output and emit something like this:

@Directive({ selector: '[myFocusDirective]' })
export class FocusDirective {
@Output() myFocusDirective = new EventEmitter<MouseEvent>(); 

constructor(private elementRef: ElementRef) {}

@HostListener('focus')
onFocus() {
    this.myService.myStream$
        .pipe(first())
        .subscribe((value => {
            this.myFocusDirective.emit(value);;
        }))
}

and then to component

<input (myFocusDirective)="openDropdown()" type="text" />

Upvotes: 1

Related Questions