Communication between custom directive and component in Angular2

10,930

You can create an @Input() someName: SomeType in your directive and bind it to a field or function in the parent component like

<div [mySelectedColor]="color" 
    [someName]="someFieldInParent"> I'm {{color}} color </div>

Another way is to query the directive in the parent component and invoke functions or set fields directly.

export class AppComponent{
  @ViewChild(selectedColorDirective) myDirective: selectedColorDirective;

  ngAfterViewInit() {
    myDirective.changeColor('red');
  }
}

You can also bind directly to class and assign CSS by using these class selectors.

See for example this http://plnkr.co/edit/nm8RgxMtqdEDyQWQGeUp?p=preview

Using a binding as selector at the same time is not supported currently, therefore you have to list the directive selector and the property you bind to each. Only [(myDirective)]="someField" seems to be supported.

I used

host: {
  '(keyup)': 'changeColor()',
  '[style.color]': 'selectedColor', // <==
}

for setting the style (I also changed the AppComponent to use this way). This is preferred to using ElementRef and Renderer. I used ElementRef and Renderer for the <span> tag though because I don't see another way from the directive on another element.

Share:
10,930
nyks
Author by

nyks

Updated on June 15, 2022

Comments

  • nyks
    nyks almost 2 years

    I have a template which has textbox, one 'span' tag and one 'div' tag.

    'div' tag has 'selectedColor' custom directive. I want to change background color of 'span' and 'div' tags when input value is changed.

    So finally I want my directive to react on input change and sets background color of 'div' tag.

    I also want to change 'span' background color on input value change event.

    Plunker

    boot.ts

    import {Component,bind} from 'angular2/core';
    
    import {bootstrap} from 'angular2/platform/browser';
    import {FORM_DIRECTIVES} from 'angular2/form';
    import {selectedColorDirective} from 'src/directive';
    import {Directive, ElementRef, Renderer, Input} from 'angular2/core';
    
    @Component({
      selector: 'my-app',
      template: `
          <input type="text" [(ngModel)]="color"  />
          <br>
          <span > I'm {{color}} color <span>
          <div [mySelectedColor]="color"> I'm {{color}} color </div>
        `,
        directives: [selectedColorDirective]
    })
    
    export class AppComponent{
    
      color:string;
      constructor(el:ElementRef,renderer:Renderer)
      {
        this.color="Yellow";
        renderer.setElementStyle(el, 'backgroundColor', this.color);
      }
     }
    
        bootstrap(AppComponent, []);
    

    directive.ts

    import {Directive, ElementRef, Renderer, Input} from 'angular2/core';
    
    @Directive({
    
      selector:"[mySelectedColor]", 
        host: {
        // '(keyup)': 'changeColor()',
        '(blur)': 'changeColor()',
      }
    
      })
    
      export class selectedColorDirective{ 
    
        @Input('mySelectedColor') selectedColor: string;
    
        constructor(el: ElementRef, renderer: Renderer) {
            //el.nativeElement.style.backgroundColor = 'yellow'; 
           renderer.setElementStyle(el, 'backgroundColor', this.selectedColor);
        } 
    
        changeColor(color:string)
        {
           console.log('Changed Detection' + " " + selectedColor);
           //this.renderer.setElementStyle(this.el, 'backgroundColor', this.color);
         }
      }
    

    Moreover if you could explain more about @Input decorator.

  • nyks
    nyks over 8 years
    I want to do it through custom directive only to explore more about it.
  • Vlado Tesanovic
    Vlado Tesanovic over 8 years
    This should be constructor of directive. For your span, you can use *ngStyle to set background on current value of color var
  • Günter Zöchbauer
    Günter Zöchbauer over 8 years
    Modifying an element <span> from a directive that is added to another tag is IMHO a pretty bad idea. Is that really what you want?
  • nyks
    nyks over 8 years
    Answer is great. but how can I call changeColor function written in directive when I change component's input field value and change bgcolor with ElementRef and Rendrer? is it possible?
  • Günter Zöchbauer
    Günter Zöchbauer over 8 years
    What do you mean by "call"? You don't want to use binding but directly call the method? Like shown here stackoverflow.com/questions/34846048/… ?
  • Günter Zöchbauer
    Günter Zöchbauer over 8 years
    Not sure if this is what you want plnkr.co/edit/QUf67I6qsQYk7n2gQAI9?p=preview I added a binding for the blur event (<input type="text" [(ngModel)]="color" (blur)="changeColor()" />) and I added the binding to selectedColor (<div mySelectedColor > (div) I'm {{color}} color </div>) because otherwise the binding and the background color set by the function call interfere. I also changed changeColor to set the color passed as argument instead of the one bound to selectedColor. Hope this helps.
  • Ng2-Fun
    Ng2-Fun about 7 years
    @GünterZöchbauer - hey, do you know how to call the component class method when I was inside its directive?
  • Adrian
    Adrian over 5 years
    it's about directive communication instead of a specific directive type implementation, right?