Apply attribute directive on component in Angular 4
Asked Answered
S

2

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.

Sancha answered 15/5, 2017 at 14:19 Comment(2)
please consider accepting my answer if it helpedMablemabry
the only problem is your src input is marked as private.Add a setter method or make your input publicRodas
M
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.

Mablemabry answered 21/5, 2017 at 17:4 Comment(0)
M
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

Mealworm answered 21/5, 2017 at 20:34 Comment(4)
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 ngIfTheomachy
@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.Zoellick
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.Theomachy
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.Zoellick

© 2022 - 2024 — McMap. All rights reserved.