13

Do you guys know how I can batch inject style declarations in a component using the @HostBinding decorator? What I am trying is:

@HostBinding('style')
get style(): CSSStyleDeclaration {
  return {
    background: 'red',
    color: 'lime'
  } as CSSStyleDeclaration;
}

In my understanding this should inject the background and color style to the component, but it does not...

I can control individual style declarations like this:

@HostBinding('style.background') private background = 'red';

but I would like to do it for all of them, please help :P

this is the full code:

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>Hello world!</h2>
    </div>
  `,
})
export class App {

  // This works
  @HostBinding('style.color') private color = 'lime';

  /* This does not work
  @HostBinding('style')
  get style(): CSSStyleDeclaration {
    return {
      background: 'red'
    } as CSSStyleDeclaration;
  }
  */

  constructor() {}
}

and a working plunker: https://plnkr.co/edit/CVglAPAMIsdQjsqHU4Fb?p=preview

5
  • What styles did you try to inject? What does "does not work" mean exactly? Commented Sep 11, 2017 at 8:05
  • nothing happens, no erors and the styles(background and color) do not get applied. I think that my syntax might be wrong or the style attribute might not be available for binding to using the HostBinding decorator. Commented Sep 11, 2017 at 8:07
  • Please add the CSS style you try to apply and the HTML where you want it applied (minimal example that allows to reproduce). Commented Sep 11, 2017 at 8:08
  • sorry about that I am not that used to stackoverflow, I added all the code and a working plunker example, hope that helps. Commented Sep 11, 2017 at 8:31
  • Thanks, Plunker is very helpful. Commented Sep 11, 2017 at 8:52

2 Answers 2

20

You need to pass the same value you would add to an element like <div style="..."> and sanitize the styles

  @HostBinding('style')
  get myStyle(): SafeStyle {
    return this.sanitizer.bypassSecurityTrustStyle('background: red; display: block;');
  }

  constructor(private sanitizer:DomSanitizer) {}

working demo

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

6 Comments

The plunker says /* this does not work */, any update
Copying to a new Plunker would probably do to get the Angular version updated. I'll have a look when I have a bit of time (no guarantees)
@BenTaliadoros Demo was broken. Fixed it.
@GünterZöchbauer Yes, here you go - stackblitz.com/edit/style-hostbinding-demo
How can you set multiple definitions for the same style, e.g. cursor: grab; cursor: -webkit-grab
|
0

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

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.