Nate
Nate

Reputation: 7856

Create css class for whole document with angular

In my CSS file, I have a class:

.test{
   background: red;
}

But at the beginning of my app, I'd like to redefine this class based on the server response such that the background becomes blue or green depending on a variable.

It is very important to attribute to this class (.test) the new color as many of my elements have already this class and I don't want to apply a new class to them.

Not sure it's very clear but to summarize, I want to create a class from javascript (using angular 2) that will apply to the whole document.

Upvotes: 1

Views: 1615

Answers (2)

diopside
diopside

Reputation: 3062

EDIT (bc I was confused on your requirements initially) -

I don't think there's a good way to modify the global styles file after the application loads, but if I am wrong on that someone please correct me.

The shadow DOM makes this tricky. I would provide a runtime configuration variable to your module and then conditionally add a class to your application's root component.

 <div class="outer-app-wrapper"  [ngClass]="someValue">

Then in your global styles.css file, you can just define all the different variations of .test there could be.

.someValue1 .test { 
     background: red;
}

.someValue2 .test {
     background: green;
 }

 .someValue3 .test {
     background: yellow;
 } 

I think if you define all the variations in the styles.css file, you should be able to avoid having to use the 'host-context:' selector in the descendant components. There's no need to add any class to an element outside of Angular's scope like the 'body' element, just add it to the top-most element of your app, and as long as descendant components don't redefine the test class as it is defined in the global stylesheet, it should work fine.

Note - you could also use @HostBinding to add the classes to your root component if you don't want to add a wrapper element or modify an existing one

Upvotes: 1

Daniel Gimenez
Daniel Gimenez

Reputation: 20494

The code below will find any style rules (including those inside media rules) that are part of the document, and overwrite any styles that are matched by the selector.

You can call modifyStyles('.test', { 'background': 'blue' }) on an instance of the service to make all styles with the .test class to have a blue background. You probably want to play with the way the selector functions, because in its current implementation any rule that has .test anywhere within it will have its background changed. You might prefer changing the regex to ^.test$ so that it matches .test and only .test.

@Injectable()
export class CssUpdateService {
    constructor( @Inject(DOCUMENT) private document: Document) {
    }
    modifyStyles(selector: string, styles: any) {
        const rulesToUpdate = this.findRules(new RegExp(`\b${selector}\b`, 'g'));
        for (let rule of rulesToUpdate) {
            for (let key in styles) {
                rule.style[key] = styles[key];
            }
        }
    }
    /**
     * Finds all style rules that match the regular expression
     */
    private findRules(re: RegExp) {
        let foundRules: CSSStyleRule[] = [];

        let ruleListToCheck = Array.prototype.slice.call(this.document.styleSheets);
        for (let sheet of ruleListToCheck) {
            for (let rule of (<any[]>(sheet.cssRules || sheet.rules || []))) {
                if (rule instanceof CSSStyleRule) {
                    if (re.test(rule.selectorText)) {
                        foundRules.push(rule);
                    }
                }
                else if (rule instanceof CSSMediaRule) {
                    ruleListToCheck.push(rule);
                }
            }
        }
        return foundRules;
    }
}

Upvotes: 1

Related Questions