4

I want to dynamically set style for child host component element from parent.

There is a solution to do it individually for each style as:

@HostBinding('style.width') @Input() width = 'auto'

But this way i need to make multiple lines for different styles.

Bellow is a solution to do this with Host binding and input combination.

2 Answers 2

4

ngStyle is designated for this.

<app-button [ngStyle]="{ marginTop: '10px', marginLeft: '50px' }">Some button</app-button>

Of course, instead of hard coding it into the template like this you could outsource it into the controller.

https://angular.io/api/common/NgStyle

PS: Since style already exists on all elements I'm not sure of the behavoiur of your code

Sign up to request clarification or add additional context in comments.

1 Comment

Yea, this is a good point. Maybe use custom host binding makes sense if you want to filter out some styles. As for the behaviour of [styles] attribute, it works as expected.
4

Here is a solution that can cover if you want to pass multiple css styles as string or as object with cammelCase conventions:

Parent HTML

<app-button [style]="styleFromParent">Some button</app-button>

Parent component has styleFromParent property and it has simulation if that property is changed at some point:

Parent Component TS

import { Component, OnInit, ChangeDetectorRef } from '@angular/core';

@Component({
  selector: 'app-site-panel',
  templateUrl: './site-panel.component.html',
})
export class SitePanelComponent implements OnInit {
  constructor(private _detectChanges: ChangeDetectorRef) {}
  styleFromParent = { marginTop: '10px', marginLeft: '50px' };

  ngOnInit() {
    setTimeout(() => {
      this.styleFromParent = { marginTop: '20px', marginLeft: '1px' };

      this._detectChanges.detectChanges();
    }, 2000);
  }
}

Child HTML

<ng-content></ng-content>

Child Component TS

In child component part that does parsing if typeof style === 'object' is to parse cammelCase styles into dash based styles and concat them into one line string.

import { Component, OnInit, HostBinding, Input } from '@angular/core';
import { DomSanitizer, SafeStyle } from '@angular/platform-browser';

@Component({
  selector: 'app-button',
  templateUrl: './button.component.html',
})
export class ButtonComponent implements OnInit {
  @HostBinding('style') baseStyle: SafeStyle;
  
  @Input()
  set style(style: string | object) {
    let mappedStyles = style as string;

    if (typeof style === 'object') {
      mappedStyles = Object.entries(style).reduce((styleString, [propName, propValue]) => {
        propName = propName.replace(/([A-Z])/g, matches => `-${matches[0].toLowerCase()}`);
        return `${styleString}${propName}:${propValue};`;
      }, '');

      this.baseStyle = this.sanitizer.bypassSecurityTrustStyle(mappedStyles);
    } else if (typeof style === 'string') {
      this.baseStyle = this.sanitizer.bypassSecurityTrustStyle(mappedStyles);
    }
  }

  constructor(private sanitizer: DomSanitizer) {}

  ngOnInit() {}
}

Above you can see that baseStyle has HostBinding to style component binding. When style input is passed setter will triger, check if string or object is passed, parse it to string and sanitize that css and assign it to baseStyle thus host style will change.

EDIT:

As @Scorpioo590 said, this is replacable with [ngStyle]. So this seems unneeded. Maybe at least this can show what can you do with style and HostBinding.

1 Comment

wasnt unneeded for me as i wanted to set host from child based on component input. awesome to have this!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.