Dynamically Set a CSS Property Based on a Template Value

Dynamically set a CSS property based on a template value

Answering my own question: The template needed to be expanded (from {{> projects}}) to allow for conditional rendering.

<div class="board">
<div class="header">
<span class="name">Project</span>
<span class="status">Status</span>
</div>
{{#each projects}}
<div class="project">
<span class="name">{{name}}</span>
<span class="status" style="color:{{getStatusColor status}}">{{status}}</span>
</div>
{{/each}}
</div>

For completeness, the helper function getStatusColor looks like this:

Handlebars.registerHelper('getStatusColor', function(status) {
switch (status) {
case "GOOD" : {
return 'green';
}
break;
case "BAD" : {
return 'red';
}
break;
default : {
...etc.;
}
});

UPDATE:
In the interests of honesty, I should confess I totally missed that I already had this expanded template in my code and that {{> projects}} was pointing to this. I should have just added the style="color:{{getStatusColor status}}" attribute directly into the referenced project template. So, as much for my benefit as others, the final, working, HTML:

<template name="foo">
<div class="board">
<div class="header">
<span class="name">Project</span>
<span class="status">Status</span>
</div>
{{#each projects}}
{{> project}}
{{/each}}
</div>
</template>

<template name="project">
<div class="project {{selected}}">
<span class="name">{{name}}</span>
<span class="status"style="color:{{getStatusColor status}}">{{status}}</span>
</div>
</template>

Generate dynamic css based on variables angular

Direct approach available in angular is using ngstyle as follows

<div [ngStyle]="{'color': style.colorVal ? style.colorVal : '#000', 'font-size' : style.fontSize ? style.fontSize : '16px' }"></div>

After going through different methods and approached to add dynamic css to all pages on angular app I ended up with following solutions.

Requirement : generate dynamic css based on values returned from and API to change design and styling.

Solution :

  1. create a new component and create a service to load dynamic css variables from API.
  2. Add style tag in template file and use variable values for properties.
  3. Load this template on all pages or on main template.
  4. On app build style will be moved to head tag.

Code sample

import { CssService} from './Css.service';

@Component({
selector: 'DynamicCss',
templateUrl: './DynamicCss.component.html',
styleUrls: ['./DynamicCss.component.scss']
})
export class ServiceProviderComponent implements OnInit {
cssVariables: any;
constructor(private cssService:CssService){
/* call the service/api to get the css variable values in cssVariables */

}
}

Now apply css using jquery or javascript to append css with help of function like following

appendCss(customData)
{
let text = '.custom-form-1 {
background-image: url("`+customData.background_image+`");
}';
$(document).ready(function(){
$("style").append(text);
});
}

and call this function after loading custom data from service or other variable like I did it ngOnInit

ngOnInit(){
this.appendCss(this.customizeFormData);
}

Its using jquery but can be done with javascript/typescript as well if you dont want to use jquery in your angular app

Other useful resource https://github.com/angular/angular/issues/9343#issuecomment-312035896

How to define css selector properties dynamically?

  1. Create a dynamic style in your top-most element in your template.
  2. Assign the backend response of your properties to a computed function.
  3. Set style lang to lang='scss' then use CSS varialbe function var() to set the values.

Example

<template>
<div :style="cssProps">
<div class="some-style">
Hello Mars
</div>
</div>
</template>

<script>
export default {
computed: {
cssProps() {
// backend response with your css values
let backendResponseObject = {
fontColor: "black", // you can use rgb or hex
backgroundColor: "White" // you can use rgb or hex
}

properties = {
"--brand-base": backendResponseObject.color,
"--brand-primary": backgroundColor.hex,
};

return properties;
}
}
}
</script>

<style lang="scss">
.some-style {
color: var(--brand-base);
background: var(--brand-primary);
}
</style>

Generate css dynamically via templates and placeholders

Wound up playing with this and CSS variables. I'm adding a second answer because it's very different method from my first answer and it better aligns with your original question (updating CSS variables with JS).

BUT... don't do this. :) Browser support in IE < Edge doesn't exist and it is almost certainly slower than updating an on-page <style> element though I haven't tested it. This jsperf tests various style update methods. It doesn't include innerHTML on a single style element (likely the fastest) but you can see that the following CSS DOM methods are slower than the rest.

// get the stylesheet// array position depends on how many style sheets you're loading.     // adjust as needed.var sheet = document.styleSheets[0];

// simplest method: insertRule()// setTimeout only for demo so you can see the changewindow.setTimeout(function(){ // @media all {} is a trick to insert more than one // selector and/or properties at once. Otherwise it's: // sheet.insertRule(":root", "--header-color: green"); ...repeat... sheet.insertRule("@media all { :root { --header-color: green; --main-color: orange; } }", 1);}, 1200);

// SAFER method via addCSSRule. // button and getAjaxStyles are just placeholders, obviouslyvar btn = document.querySelector('button');btn.addEventListener("click", getAjaxStyles);
function getAjaxStyles() { // success callback... break apart the json and update the CSS variables addCSSRule(sheet, ":root", "--header-color: orange"); addCSSRule(sheet, ":root", "--main-color: blue"); addCSSRule(sheet, ":root", "--alt-color: red"); addCSSRule(sheet, ":root", "--borderColorA: lavender"); // or go with a single big string. definitely faster: // addCSSRule(sheet, ":root", "--alt-color: red; --borderColorA: #0ff; ")}
// Credit for addCSSRule() goes to Diego Flórez in a comment on // https://davidwalsh.name/add-rules-stylesheetsvar addCSSRule = function(sheet, selector, rules) { //Backward searching of the selector matching cssRules var index = sheet.cssRules.length - 1; for (var i = index; i > 0; i--) { var current_style = sheet.cssRules[i]; if (current_style.selectorText === selector) { //Append the new rules to the current content of the cssRule; rules = current_style.style.cssText + rules; sheet.deleteRule(i); index = i; } } if (sheet.insertRule) { sheet.insertRule(selector + "{" + rules + "}", index); } else { sheet.addRule(selector, rules, index); } return sheet.cssRules[index].cssText;}
/* Set initial CSS variables */:root {  --header-color: #333;  --main-color: #888;  --alt-color: #bbb;  --borderColorA: #ccc;}h1 {  color: var(--header-color);}p {  border-bottom: 1px solid var(--borderColorA);  color: var(--main-color);}p+p {  color: var(--alt-color);}
<h1>header</h1><p>paragraph 1</p><p>paragraph 2</p><button>Update CSS Variables</button>

Dynamically setting value of `grid-template-columns` css property

If you follow the steps of the specification you see

setProperty
5. Let component value list be the result of parsing value for property property.

then

parsing

1.Let list be the value returned by invoking parse a list of component values from value.

then

parse a list of component values

1. Repeatedly consume a component value until an is returned, appending the returned values (except the final ) into a list. Return the list.

almost there

consume a component value

Otherwise, if the current input token is a <function-token>, consume a function and return it.

and finally

consume a function

Create a function with a name equal to the value of the current input token, and with a value which is initially an empty list.

Repeatedly consume the next input token and process it as follows:

<)-token>

Return the function.

<EOF-token> This is a parse error. Return the function.
anything else

Reconsume the current input token. Consume a component value and append the returned value to the function’s value.

in short, when it is a function it gets executed and its result is assigned.

How to dynamically set and modify CSS in JavaScript?

If I understand your question properly, it sounds like you're trying to set placeholder text in your css file, and then use javascript to parse out the text with the css value you want to set for that class. You can't do that in the way you're trying to do it. In order to do that, you'd have to grab the content of the CSS file out of the dom, manipulate the text, and then save it back to the DOM. But that's a really overly-complicated way to go about doing something that...

myElement.style.width = "400px";

...can do for you in a couple of seconds. I know it doesn't really address the issue of decoupling css from js, but there's not really a whole lot you can do about that. You're trying to set css dynamically, after all.

Depending on what you're trying to accomplish, you might want to try defining multiple classes and just changing the className property in your js.



Related Topics



Leave a reply



Submit