Angular v13: Separate Styles and Theme for 2 different parts of an Angular / Material Application

350 Views Asked by At

I am creating an angular application with 3 different parts which are accessible by 3 different types of users: admin, landowner, and buyer. The buyer section is a new section and I need to create a new theme / styles for this section. There are component specific .scss files as well as global styles which are contained in a _global.scss file and a _layout.scss file. There is also a styles.scss file which is declared in the styles section of the angular.json file with injection set to true. I only want the global styles (_global and _layout) to be accessible to admin and landowner components of the application, and not the buyer components. The admin can also access all routes, so they will be able to navigate anywhere they like. My app-routing.module routing module looks something like this:

app.component

  • '' path redirects to login.component
  • login.component
  • admin-dashboard.component
    • router-outlet with subroutes
  • admin-project.component
    • router-outlet with subroutes
  • landowner-dashboard.component
    • router-outlet with subroutes
  • buyer.dashboard.component
    • router-outlet with subroutes

So far I have tried switching the ViewEncapsulation to None for the top level components being mounted above (i.e. login.component, admin-dashboard.component, etc) in this routing module, and then importing the _global.scss and _layout.scss into each of those top level components. That works until an admin starts navigating in between sections and the styles from the admin section start to override the styles from the buyer section. I have tried to edit the angular.json to set inject: false for the global style sheets mentioned, and then importing those stylesheets for all the top level components, with the same issue. I have tried wrapping the global styles in a class, and then setting the containers for all the admin and landowner components to have this class, and the styles were not being applied. I have also followed the angular guides for creating multiple themes, and the styles were not being applied (there would also be too much code to paste here). Has anyone run into this type of problem and know how to get it to work at a high level?

3

There are 3 best solutions below

0
On

I think what you are looking for are module scoped style, unfortunately this is not a feature currently available.

0
On

I got it working using @robbieAreBests answer and without setting ViewEncapsulation to None. I had to alter the router subscription in the app.component slightly because I am trying to get the data object from a child route within a <router-outlet>

 constructor(
    private router: Router,
    private route: ActivatedRoute,
    private elementRef: ElementRef
  ){
    this.router.events.subscribe((data) => {
      if (data instanceof RoutesRecognized) {
        this.elementRef.nativeElement.ownerDocument.body.className = data.state.root.firstChild.data['theme'];
      }
    });
  }
3
On

I currently do the following for theme swapping and this may be helpful for your situation:

In my routes, I add a 'theme' field to the route data, something like:

  {
    path: 'admin',
    component: AdminComponent,
    data: {
      theme: 'admin'
    }
  }

In app.component.ts I subscribe to router changes, and the set a class on the applications body tag for my theme value

this.router.events.pipe(filter((event) => event instanceof NavigationEnd))
.subscribe(() => {
      this.elementRef.nativeElement.ownerDocument.body.className = route.snapshot.data['theme'];
});

Lastly, in my top level style I can apply style and themes nested in these theme classes that will override the base theme

$primary: mat-palette($mat-blue, 500, 300, 700); 
$accent: mat-palette($mat-gray, 200);
$warn: mat-palette($mat-red, A700, 50);
$theme: mat-light-theme($primary, $accent, $warn);
@include angular-material-theme($theme);

// additional default/base style

.admin {
   $admin-primary: mat-palette($mat-green, 500, 300, 700); 
   $admin-theme: mat-light-theme($admin-primary, $accent, $warn);
   @include angular-material-theme($admin-theme);

   // Additional custom style
}