8

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.

Naveen raj
  • 891
  • 1
  • 10
  • 18

2 Answers2

4

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.

Max Koretskyi
  • 101,079
  • 60
  • 333
  • 488
1

Directives are only instantiated for selectors that match HTML which is added to components templates statically.
There is no way to add/remove directives from an element dynamically. The only way is to add/remove the whole element (for example using *ngIf

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • Can class selector directive will apply to all those elements which will added to dom latter on when ngIf condition will come to true. Because, right now, directive will apply to only visible dom elements and not which will added to dom by ngIf – Developer May 14 '21 at 07:32
  • @GaurangDhorda yes, if the content is added/removed by Angular then the directives will be applied. Important is that Angular can see the HTML when it compiles the components. If the HTML is added at runtime by some custom code, Angular won't be aware of the new content and won't apply directives. If you want to have such components were HTML is composed at runtime, you can add the dynamic Angular runtime which includes a template compiler that can compile components at runtime. This is used rather rarely, but it's possible. – Günter Zöchbauer May 14 '21 at 08:21
  • Thank You. My use case is.. I have one select-dropdown component, when we click or open dropdown by keyboard then dropdown will open with one textbox and list to choose. textbox is used to search inside all available lists. I want to auto-focus this textbox when we open dropdown by clicking or by keyboard, when its open textbox must be focused. To do this, Now, I need to use `document.getElementByClassName()` and I want to replace this part to directive. How could I do? Or is there any better way ? Thank You. – Developer May 14 '21 at 09:24
  • 1
    I think it's better to open a new question with code that demonstrates what you try to accomplish, what you tried, and where you're stuck. – Günter Zöchbauer May 15 '21 at 18:11