Kugel
Kugel

Reputation: 19814

How to apply css class to a component element when it's created by router-outlet?

I have DOM that looks something like this:

<app>
    <router-outlet></router-outlet>
    <project>...</project>
</app>

where project element is inserted by the router.

How do I add a class to this element?

Upvotes: 67

Views: 51807

Answers (15)

After the deprecation of ::ng-deep in Angular, the proper way to use the solution provided in @Val's comment is to set the style in a CSS not bind to a specific component.

Usually, you have in your angular.json file a list of styles declared as follows:

 "projects": {
    "n9-skeleton-ng-cli": {
      "root": "",
      "architect": {
        "build": {
          "options": {
            "styles": [
              "src/app/app.module.scss"
            ]
          }
       }
    }

In one of these styles files, use a selector that will target that router specifically and add the sibling selector.

For instance, to not target every router-outlet in the application, you can add a class on the targeted ones .router-styled , then target it: in src/app/app.module.scss

router-outlet.router-styled + * {
    /* your css */
}

Upvotes: 0

KingMario
KingMario

Reputation: 171

I know it's late.

I created this directive to allow you to set (static) or bind (dynamic) classes to each component that is injected by Angular next to the router-outlet element:

https://www.npmjs.com/package/ngx-router-outlet-class

Please upvote my feature request if you DO think it's necessary to have such a built-in functionality.

Upvotes: -1

Lewis99
Lewis99

Reputation: 31

it's simple, let's say in your app component you have a
<router-outlet ></router-outlet>

inside this router-outlet you have a route component called <app-product-detail></app-product-detail>

and you want to change the view of in the app.component.html.

first inside the the component <app-product-detail> add this snippet:

@Component({


selector: 'app-product-detail',
  host: {
    class:'Project-wrapper'
},
  templateUrl: './product-detail.component.html',
  styleUrls: ['./product-detail.component.css']
})```

class= 'could be any name'

inside app.component.css you add this snippet below:

    ::ng-deep .Project-wrapper { 
width: 85%;
        background-color: aqua;
    }

Upvotes: 0

Jitendra Mehta
Jitendra Mehta

Reputation: 17

Add host class name which will add a class to the component then use adjacent to target the element.

@Component({
  selector:'project',
  host: {
      class:'Project-wrapper'
  }
})

now use CSS adjacent with angular

::ng-deep to target it:
::ng-deep .Project-wrapper {}

Upvotes: 0

drew moore
drew moore

Reputation: 32670

Assuming you always want the class applied to this component, you can use host in your component metadata:

@Component({
  selector:'project',
  host: {
      class:'classYouWantApplied'
  }
})

Resulting in:

<app>
    <router-outlet></router-outlet>
    <project class="classYouWantApplied">...</project>
</app>

Upvotes: 78

Rias
Rias

Reputation: 1996

For me it helped to wrap the router-outlet into another container.

<div class="classYouWantApplied">
  <router-outlet>
</div>

Like this you could apply the class to the surrounding container.

Upvotes: 3

Shay
Shay

Reputation: 1305

since router injects the component after the the router-outler element, if we would like to style all injected component with the same set of rules the folowing rule is can be helpful.

the css "+" operator select the first sibling element of a certain type, while asterisk (*) is used as a wild card to select any 1st sibling of router-outlet

router-outlet + * {
  // your rules
}

Upvotes: 4

Simon_Weaver
Simon_Weaver

Reputation: 145890

I created a RouterOutletHelperDirective which can be modified as necessary.

Your use-case may be different but for me :

  • I needed to set a default set of classes on each router-outlet generated item
  • I needed to prevent this default based on certain conditions, such as ActivatedRoute data.

You use it like this (the class is optional):

<router-outlet routerOutletHelper
               [routerOutletHelperClass]="'blue-border'"></router-outlet>

Then create the directive, add and export it to your app module.

import { Directive, ElementRef, Renderer2, Input } from "@angular/core";
import { RouterOutlet } from "@angular/router";
import { Subscription } from "rxjs";

@Directive({
    selector: 'router-outlet[routerOutletHelper]'
})
export class RouterOutletHelperDirective
{
    constructor(private routerOutlet: RouterOutlet,
                private element: ElementRef<HTMLElement>,
                private renderer: Renderer2) { }

    subscription = new Subscription();

    @Input('routerOutletHelperClass')
    customClassName: string | undefined;

    ngOnInit() 
    {
        this.subscription.add(this.routerOutlet.activateEvents.subscribe((_evt: any) => {

            // find the component element that was just added
            const componentElement = this.element.nativeElement.nextSibling;

            // add a custom class
            if (this.customClassName) 
            {
                this.renderer.addClass(componentElement, this.customClassName);
            }

            // add my default classes, unless the activated route data 
            // (specified in module routing file) has { addDefaultClasses: false }
            if (this.routerOutlet.activatedRouteData && this.routerOutlet.activatedRouteData.addDefaultClasses !== false)
            {
                // these are my application's default classes (material / theming)
                // (an additional data parameter could be 'darkTheme: boolean')
                this.renderer.addClass(componentElement, 'mat-typography');
                this.renderer.addClass(componentElement, 'rr-theme-light');
            }
        }));
    }

    ngOnDestroy()
    {    
        this.subscription.unsubscribe();
    }
}

Upvotes: 1

Dmytro K.
Dmytro K.

Reputation: 169

Currently, Angular 6 recommends me to use @HostBindings and @HostListeners instead of the host property:

export class ProjectComponent {
  @HostBinding('class') classes = 'classYouWantApplied';
}

Upvotes: 5

JED
JED

Reputation: 1694

use the adjacent sibling selector and the * wildcard to select the element immediately following the router-outlet


styles.css

router-outlet + * {
  /* your css */
}

enter image description here

Upvotes: 29

Awinash jaiswal
Awinash jaiswal

Reputation: 319

<app>
  <div class="your css class">
   <router-outlet></router-outlet>
</div>
</app>

This works for me

Upvotes: 5

Val
Val

Reputation: 22797

The key is /deep/ keyword:

    :host /deep/ router-outlet + project {
        display: block;
        border: 10px solid black;
    }

This works without any extra configurations.

:host /deep/ router-outlet + * for whatever component dynamically created by Angular Router.

Edited 2018/3/5:

Since Angular 4.3.0 made /deep/ deprecated, its suggested alternative is ::ng-deep. And there were a long discussion about this.

Upvotes: 14

lordchancellor
lordchancellor

Reputation: 4105

You can do this with a HostBinding, which is effectively the same as using the host property that has already been mentioned, although that method throws a TSLint error with default listing rules.

In your component on which you want to apply a class:

import { Component, HostBinding, Host (optional for typing) } from '@angular/core';

@Component({...})
export class GiveMeAClassComponent {
    @HostBinding('class.some-class') someClass: Host = true;
    ...
}

And then in your root styles.scss file, you can add the following:

.some-class {
    // Styles in here will now be applied to your GiveMeAClassComponent at a root level
}

Upvotes: 6

adamdport
adamdport

Reputation: 12603

If you need to add a class conditionally, you can add it programmatically from the component:

constructor(private renderer: Renderer2, private elemRef: ElementRef) {
  if(someCondition){
    renderer.addClass(elemRef.nativeElement, 'myClass');
  }
}

Upvotes: 3

G&#252;nter Z&#246;chbauer
G&#252;nter Z&#246;chbauer

Reputation: 657168

You can use the adjacent sibling selector

router-outlet + project { ... }

https://developer.mozilla.org/en/docs/Web/CSS/Adjacent_sibling_selectors

but only if @drewmoore's approach doesn't apply.

Upvotes: 5

Related Questions