Apply attribute directive on component in Angular 4

Naveen raj picture Naveen raj · May 15, 2017 · Viewed 7.5k times · Source

I have created img-pop component which has @Input() bind property src. I have created authSrc directive which has @HostBinding() property src.

@Component({
selector: 'img-pop',

template: `<img [src]="src"/>
            <div *ngIf="isShow">
                 <----extra value----->
            </div>`
})

export class ImgPopOverComponent implements OnInit {

@Input()
private src;

private isShow=false;

@HostListener('mouseenter') onMouseEnter() {
    this.isShow= true;
}

@HostListener('mouseleave') onMouseLeave() {
    this.isShow= false;
}

}

I have directive like this.

@Directive({ selector: '[authSrc]' })
export class AuthSrcDirective implements OnInit {

@HostBinding()
private src: string;

constructor(private element: ElementRef) { }

ngOnInit() { }

  @Input()
  set authSrc(src) {
   this.src = src+"?access_token=<-token->";
  }
}

i want to combine both functionality in one like.

<img-pop [authSrc]="/api/url/to/image"></img-pop>

so that final url call will be /api/url/to/image?access_token= <--token-->

but it throws Can't bind to 'src' since it isn't a known property of 'img-pop'. error

plnkr link

Please correct me if i am wrong with conceptual.

Thank you.

Answer

Max Koretskyi picture Max Koretskyi · May 21, 2017

According to this answer by the core contributor it's impossible to set direct properties of the component using @HostBinding. @HostBinding always binds directly to the DOM. So this is by design. Here is the explanation:

This works as intended, as:

  • using data binding to communicate between directives / components on the same element is slower than direct communication by making one inject the other data
  • binding between directives easily leads to cycles.

So, in your case, this is the possible solution:

export class AuthSrcDirective {
    // inject host component
    constructor(private c: ImgPopOverComponent ) {    }

    @Input()
    set authSrc(src) {
        // write the property directly
        this.c.src = src + "?access_token=<-token->";
    }
}

For a more generic approach, see this.