112
votes

How can I add a class to the body tag without making the body as the app selector and using host binding?

I tried the using the Renderer but it changes the whole body

Angular 2.x bind class on body tag

I'm working on a big angular2 app and changing the root selector will impact a lot of code, I will have to change a lot of code

My use case is this:

When I open a modal component (created dynamically) I want the document scrollbar to hide

2
Actually if you work with js within html page what is the problem with using document.body.className|classList?yurzui
haha if only it was that simple :) but it's a bad practice to access dom directlyRachid Oussanaa
You can write a big wrapper that will be executed several second and at the end added class to body. If you are not going to use server rendering or web worker what you're afraid of?yurzui
so there's no better solution than this ?Rachid Oussanaa
I can't understand these abusive people who downvote and close questions for no valid reasonRachid Oussanaa

2 Answers

241
votes

I would love to comment. But due to missing reputation I write an answer. Well I know two possibilities to solve this issue.

  1. Inject the Global Document. Well it might not be the best practice as I don't know if nativescript etc supports that. But it is at least better than use pure JS.
constructor(@Inject(DOCUMENT) private document: Document) {}

ngOnInit(){
   this.document.body.classList.add('test');
}

Well and perhaps even better. You could inject the renderer or renderer 2 (on NG4) and add the class with the renderer.

export class myModalComponent implements OnDestroy {

  constructor(private renderer: Renderer) {
    this.renderer.setElementClass(document.body, 'modal-open', true);
   }

  ngOnDestroy() {
    this.renderer.setElementClass(document.body, 'modal-open', false);
  }

EDIT FOR ANGULAR4:

import { Component, OnDestroy, Renderer2 } from '@angular/core';

export class myModalComponent implements OnDestroy {

  constructor(private renderer: Renderer2) {
    this.renderer.addClass(document.body, 'modal-open');
   }

  ngOnDestroy() {
    this.renderer.removeClass(document.body, 'modal-open');
  }
57
votes

I think the best way to do it is a combination of both approaches by DaniS above: Using the renderer to actually set / remove the class, but also using the document injector, so it is not strongly dependant on the window.document but that can be replaced dynamically (e.g. when rendering server-side). So the whole code would look like this:

import { DOCUMENT } from '@angular/common';
import { Component, Inject, OnDestroy, OnInit, Renderer2 } from '@angular/core';

@Component({ /* ... */ })
export class MyModalComponent implements OnInit, OnDestroy {
    constructor (
        @Inject(DOCUMENT) private document: Document,
        private renderer: Renderer2,
    ) { }

    ngOnInit(): void {
        this.renderer.addClass(this.document.body, 'embedded-body');
    }

    ngOnDestroy(): void {
        this.renderer.removeClass(this.document.body, 'embedded-body');
    }
}