Ran Roslan Bobkov
Ran Roslan Bobkov

Reputation: 53

Angular 4 - Styling component with variables

I would like to know if it's possible to style a component through the 'styles' property of angular's @component object.

Here is an example of what I'm trying to achieve, pay attention to the {{ratio}} variable in 'styles' property.

@Component({
 selector: 'img-thumb',
 templateUrl: './img-thumb.component.html',
 styleUrls: ['./img-thumb.component.css'],
 styles: [`
   :host:after{
     content: '';
     display: block;
     padding-bottom: {{ratio}};
   }
 `],
 host: {
  '[style.height.px]' : 'height',
  '[style.padding.px]' : 'gap'
 } 
})

export class ImgThumbComponent implements OnInit {

 @Input() height : any
 @Input() gap : any
 @Input() ratio : any

 //More code...

 }

Basically I'm trying to implement :after on the host with a variable. If it's possible, I prefer to implement it inside the .ts file of the component.

Upvotes: 1

Views: 2038

Answers (1)

Miquel Canal
Miquel Canal

Reputation: 1121

As it is not possible to add inline pseudo-element styles, one workaround would be to use Angular's renderer2 methods to create a new <style> tag and append it to the DOM at runtime. Here's a component:

import { Component, ElementRef, ViewChild, OnInit, Renderer2 } from '@angular/core';

@Component({
    selector: 'app-component',
    template: '<div #stylesContainer></div>'
})
export class singleComp implements OnInit{
    // Get destination container
    @ViewChild("stylesContainer") private stylesDist: ElementRef;

    // Define variable values
    height: string = "150px";
    gap: string = "30px";
    ratio: string = "10px";

    // Create the actual CSS style and store it in variables
    styleClass = ".class{ height: "+this.height+"; padding: "+this.gap+"}";
    pseudoStyle = ".class:after{content: '';display: block;padding-bottom: "+this.ratio+"}";

    constructor(private renderer: Renderer2) {}

    ngOnInit() {
        // Dynamically create the CSS tags
        const classStyle = this.renderer.createText(this.styleClass);
        const pseudoElementStyle = this.renderer.createText(this.pseudoStyle);

        // Insert the previously defined style into a new <style> element
        const newStyleElement = this.renderer.createElement('style');
        this.renderer.appendChild(newStyleElement, classStyle);
        this.renderer.appendChild(newStyleElement, pseudoElementStyle);
        this.renderer.appendChild(this.stylesDist.nativeElement, newStyleElement);
    }
}

In the component above the variables height, gap and ratio are hardcoded, but you can get them via @input. The HTML template contains a div with the local reference #stylesContainer this will be the destination element on where to dynamically append the styles.

When the component initialises, it generates a new <style> tag containing the dynamic styles including the pseudo-element ones. Then using the Renderer2 from Angular, it appends the new <style> tag back into the <div #stylesContainer> which you get from using @ViewChild

Upvotes: 1

Related Questions