Search code examples
angularangular2-hostbinding

Angular 2 : @HostBinding with an Input object property


Is it possible to bind a @HostBinding value like this example ?

@Input() user: User;
@HostBinding("class.temp") user.role == "Admin"

I know I can do this :

private _user: User;
@Input() set user(user: User) {
    this._user = user;
    this.temp = (this._user.role == "Admin");
}
@HostBinding("class.temp") temp: boolean;

but in this case, if my user change his role, the value will never be updated in this component. How to do this ?


Solution

  • This is how I do a host binding on an object property:

    @Input()
    public user: User;
    
    @HostBinding('class.example')
    public get isExample(): boolean {
         return this.user && this.user.role === 'admin';
    }
    

    If you find yourself stuck, and just need to get the feature working. You can check for role changes on every change detection using the DoCheck interface. This tells Angular to call ngDoCheck for every change detection.

    @Input()
    public user: User;
    
    @HostBinding('class.example')
    public isExample: boolean;
    
    public ngDoCheck(): void {
         this.isExample = this.user && this.user.role === 'admin';
    }
    

    The above adds overhead to the application, and isn't a best practice.

    You should separate the input into User and role like this:

    @Input()
    public user: User;
    
    @Input()
    public role: string;
    
    @HostBinding('class.example')
    public get isExample(): boolean {
        return this.role === 'admin';
    }
    

    That's the easiest solution. As it uses Angular's own change detection.

    Another solution is to make the user object immutable. This way a new user object is created every time a property is changed. This will also trigger change detection in Angular, and is the preferred way of working with objects in bindings.

    With that said, immutable has limits and can be a pain to work with.

    There are other solutions such as custom observables and using ChangeDetectRef to tell the component something has changed. Those solutions are more involved and I think components should be kept simple.

    I try to follow the primitive binding rule. Where all inputs to a component are of type number or string. Avoiding arrays and objects.

    In your example, does your component really need full access to the user object or just some of it's properties? If you add inputs for each property you need then you've decoupled the component from the user object and that makes it easier to test as well.