0

I am using Angular 6 and Typescript. Here's my issue. I need to add a specific CSS rule to the host of a component that I am writing. I cannot apply that rule systematically, I need to have some logic in ngOnInit() before adding my rule. I know this sounds like bad practice, but there are no workarounds and this is the only way I can solve the problem I am facing. I can easily add classes on new styles to my host, but I cannot seem to find a way to add a rule.

Some people have been marking my question as a duplicate. Please read my question carefully. I am not trying to add a class, I am trying to a add a RULE. This is very different and there are no results for such question.

Here's the two rules I have that I want to add to my host element depending on some condition:

custom-component + custom-component > .vertical-component {
    margin-top: 1rem;
}

and

custom-component + custom-component > .horizontal-component {
    margin-left: 1rem;
}

In my component code, I have something like this:

export class CustomComponent {
    public constructor(private host: ElementRef, private renderer: Renderer2) {

    }

    public applyStylesToHost(): void {
        if (this.variant == TYPE.VERTICAL) {
            // Set the rule with the margin-top
        } else {
            // Set the rule with the margin-left
        }
    }
}

I was looking for a method like this.renderer.setRule(), but there is no such thing. How can I programmatically add a specific rule to my host element?

The closest thing I found is this link. The author suggest doing document.createElement("style").sheet.addRule(), but when I tried to do it, the method addRule didn't exist on the sheet element.

ThomasFromUganda
  • 380
  • 3
  • 17
  • 1
    Does this answer your question? [Angular: conditional class with \*ngClass](https://stackoverflow.com/questions/35269179/angular-conditional-class-with-ngclass) – Balastrong May 29 '20 at 12:25
  • @Balastrong No, the question you linked is regarding classes. I want to add a specific rule, which I have provided in the code. The closest thing I found is this: https://davidwalsh.name/add-rules-stylesheets However, it does not work for some reason. The method `addRule()` on `style.sheet` doesn't exist. – ThomasFromUganda May 29 '20 at 12:31
  • Are you looking for HostBinding? https://stackoverflow.com/questions/35168683/hostbinding-with-a-variable-class-in-angular/46207423#46207423 – Eliseo May 29 '20 at 12:35
  • @Eliseo Not really. I already found how to apply classes or styles to host. My issue is that this is the selector I want to add `custom-component + custom-component > .horizontal-component `. In plain English, I my custom-component can either by of type 'vertical' or 'horizontal'. If it is vertical, then I want to add margin-top to my host only if it is preceded by an other custom-component. – ThomasFromUganda May 29 '20 at 12:39
  • How to modify attributes classes and styles in the dom https://www.digitalocean.com/community/tutorials/how-to-modify-attributes-classes-and-styles-in-the-dom – Michael Dimmitt May 29 '20 at 12:48

3 Answers3

2

If you want to go this way, you should use probably method:

renderer.setStyle(...)

or

renderer.addClass(...)
renderer.removeClass(...)

I suggest to read documentation for Renderer2

Serkus
  • 31
  • 3
1

As Balastrong mentions you could use ngClass logicFinished = false

ngOnInit() {
  ... your logic
  this.logicFinished = true
}

[ngClass]="{'vertical-component': logicFinished, 'horizontal-component': !logicFinished}"

Alternative javascript hack to fix the problem.

this.yourElement = document.getElementById('yourElement') as HTMLElement
this.yourElement.style.margin = '1rem 0 0 0'
this.yourElement.style.margin = '0 0 0 1rem'

But NgClass seems a better solution for the problem.

Michael Dimmitt
  • 826
  • 10
  • 23
  • Unfortunately, this will not solve my issue. As mentionned, I am not trying to add a class, I am trying to add a rule with a specific selector. You can find what are the two rules I want to add conditonnally, but there are not simple classes. – ThomasFromUganda May 29 '20 at 12:37
0

Could you just add them as <style> tag to the whole document?

var st = document.createElement('style'); 
st.appendChild(document.createTextNode(`
    custom-component + custom-component > .vertical-component {
        margin-top: 1rem;
    }
`));  
document.head.appendChild(st);
Kamil Szot
  • 17,436
  • 6
  • 62
  • 65