3

For a given js variable, which has style information in it:

menuBgColor = "red";

In AngularJS I was able to use dynamically embedded style:

<div>
   <style>
      .menuElement{
         background-color:{{menuBgColor}}
      }
   </style>
   <div class="menuElement">...</div>
</div>

In Angular2+ I cannot use the same as above. When the view is rendered in the browser variable menuBgColor is not populated and the element is rendered as coded.

like this -

<body>
...other markup...
<div><style>.menuElement{background-color:{{menuBgColor}}}</style>
...markup...
</body>

I want to know that what are the other ways in angular 2+ to add dynamic styles to the view?

  • I know of ngStyle but the given example is a very small one.
  • In my case, I have to apply dynamic styles to each element of the whole app like button, borders, background, colors, tree controls, sidebars etc. So ngStyle is very exhaustive.
  • I also do not have predefined theme files because theme is managed by a feature in our app where user can define his/her own theme. Here I understand that I can refresh page to get the updated theme BUT consider that there can be 'n' number of users with their own themes.
  • So in my use case, the only solution I can think of is that somehow variable interpolate and create an embedded css.

Any help is greatly appreciated.

gyc
  • 4,300
  • 5
  • 32
  • 54
Ashwin
  • 12,081
  • 22
  • 83
  • 117

2 Answers2

2

You can try this:

<div [style.background-color]="yourVar"></div>

In this case the binding should work

axl-code
  • 2,192
  • 1
  • 14
  • 24
  • 1
    Good idea and I think this will work for many cases. But what if someone wants to set a style on a pseudo-element? Also the OP mentioned (and dismissed) ngStyle. – Raphael Schweikert Dec 18 '17 at 12:19
  • 1
    ok but there are many elements to style. It is exhaustive to add styles to around 1000 elements. – Ashwin Dec 18 '17 at 12:20
2

There's no pretty way to do this without building a huge structure like Angular Material does. But, if your theme system is not so complex, I'd simply go with a dynamically rendering of the <link> tag to your theme like so:

import { Component } from '@angular/core'
import { DomSanitizer } from '@angular/platform-browser'

@Component({
  selector: 'my-app',
  template: `
    <link rel="stylesheet" [href]="getThemeUrl()">
    <div class="main">
        {{'themes/css/'+ theme +'.css' }}

        <select [(ngModel)]="theme" (change)="onThemeChanged(theme)">
            <option value="red">Red</option>
            <option value="blue">Blue</option>
            <option value="yellow">Yellow</option>
        </select>
    </div>
  `
})
export class AppComponent {
    theme = 'red';

    constructor(public sanitizer: DomSanitizer){}

    getThemeUrl(){
        return this.sanitizer
            .bypassSecurityTrustResourceUrl('themes/' + this.theme + '.css');
    }
}

Plunkr

lenilsondc
  • 9,590
  • 2
  • 25
  • 40
  • 1
    It works perfectly, but only one problem with this is that the css file is re-requested on every UI interaction. Any way to avoid that? – Ashwin Dec 18 '17 at 12:22
  • @Ashwin maybe if you use `[href]="'/themes/css/' + theme + '.min.css'"` – lenilsondc Dec 18 '17 at 12:31
  • Having a problem with running your problem. It keep on saying "Loading...". as soon as I fix it I will update you. – Ashwin Dec 19 '17 at 08:34
  • @Ashwin anyways there's a plunkr with a working solution https://embed.plnkr.co/lsi1VPHFaLSEoZraQcAF?p=preview it's a version mismatch try to compare angular's version in the `system.config.js` file. – lenilsondc Dec 19 '17 at 10:11
  • I checked your plunkr and I am seeing one problem which I mentioned in my first comment i.e. when I have something else updating (like a variable interpolating) then the css file is requested again, if you could see that in Network tab. This gives a flickering UI on the screen. https://plnkr.co/edit/nV4WOR9efThiRs1V3gCK?p=preview – Ashwin Jan 05 '18 at 07:02