Best method to set different layout for different pages in angular 4

后端 未结 4 683
孤街浪徒
孤街浪徒 2020-12-04 06:16

I am new to angular 4. What I\'m trying to achieve is to set different layout headers and footers for different pages in my app. I have three different cases:

相关标签:
4条回答
  • 2020-12-04 06:54

    There are cases where the layout and shared elements don't really match the routing structure, or some elements have to be hidden/shown depending on a per-route basis. For such cases I can think of the following strategies (let's take an example of app-header-main component - but it will apply to any shared page element obviously):

    Inputs & css classes

    You can provide inputs or css classes to control the inner appearance of your shared elements, such as:

    1. <app-header-main [showUserTools]="false"></app-header-main>

    or

    1. <app-header-main class="no-user-tools"></app-header-main> and then use :host(.no-user-tools) to show/hide what needs to be

    or

    1. at a route level (child or not):

      {
        path: 'home',
        component: HomeComponent,
        data: {
          header: {showUserTools: true},
        },
      },
      

    And access it through ActivatedRoute like so: this.route.data.header.showUserTools

    TemplateRef input

    Inside app-header-main component:

    @Input() rightSide: TemplateRef<any>;

    Input of type TemplateRef<any> where you could feed an ng-template element directly

    <app-header-main [rightSide]="rightside"></app-header-main>
    <ng-template #rightside>your content here</ng-template>
    

    Named slot transclusion

    You can author the app-header-main so that it uses named slot transclusion

    Inside of app-header-main template:

    <ng-content select="[rightSide]"><ng-content>

    Usage:

    <app-header-main class="no-user-tools">
      <div rightSide>your content here</div>
    </app-header-main>
    
    0 讨论(0)
  • 2020-12-04 06:54

    You can solve the problem using ng-content + ViewChild injection of layout into each page component that uses that specific layout.

    Using the router for this common use case always seemed like a workaround to me. What you want is similar to Layouts in Asp.Net MVC or MasterPages in WebForm etc.

    After struggling with this I ended up with something like this:

    see working demo: https://stackblitz.com/edit/angular-yrul9f

    shared.component-layout.ts

    import { Component } from '@angular/core';
    
    @Component({
      selector: 'shared-component-layout',
      template: `
      <div *ngIf="!hideLayoutHeader" style="font-size: 2rem;margin-bottom: 10px;">
        Layout title: {{layoutHeader}}
        <ng-content select=".layout-header">    
        </ng-content>
      </div>
      <ng-content select=".layout-body">
      </ng-content>
      `
    })
    export class SharedComponentLayout {
      layoutHeader: string;
      hideLayoutHeader: boolean;
    }
    
    

    page.component-base.ts

    import { Component, ViewChild } from '@angular/core';
    import { SharedComponentLayout } from './shared.component-layout';
    
    export abstract class PageComponentBase {
        @ViewChild('layout') protected layout: SharedComponentLayout;
    }
    

    login.component.ts - without header

    import { Component } from '@angular/core';
    import { PageComponentBase } from './page.component-base';
    
    @Component({
      selector: 'login-component',
      template: `
      <shared-component-layout #layout>
        <div class="layout-body">
          LOGIN BODY
        </div>
      </shared-component-layout>
      `
    })
    export class LoginComponent extends PageComponentBase {
    
      ngOnInit() {
        this.layout.hideLayoutHeader = true;    
      }
    }
    

    home.component.ts - with header

    import { Component } from '@angular/core';
    import { PageComponentBase } from './page.component-base';
    
    @Component({
      selector: 'home-component',
      template: `
      <shared-component-layout #layout>
        <div class="layout-body">
          HOME BODY
        </div>
      </shared-component-layout>
      `
    })
    export class HomeComponent extends PageComponentBase {
    
      ngOnInit() {    
        this.layout.layoutHeader = 'Home component header';
      }
    }
    
    0 讨论(0)
  • 2020-12-04 07:00

    you can use child e.g.

    const appRoutes: Routes = [
        { path: '', component: MainComponent,
            children:{
                { path: 'home'  component:HomeComponent},
                { path: 'about', component: AboutComponent},
                { path: 'contact', component: ContactComponent},
                   ..others that share the same footer and header...
    
            }
        },
        { path: 'login', component: LoginComponent },
        { path: 'register', component: RegisterComponent },
        { path: 'admin', component:AdminComponent, 
             children{
                { path: 'dashboard', component: DashboardComponent },
                { path: 'profile', component: ProfileComponent }
                   ..others that share the same footer and header...
             }
        }
        { path: '**', redirectTo: '' }
    ];
    

    MainComponent and AdminComponent like

    <app-header-main></app-header-main>
    <router-outlet></router-outlet>
    <app-footer-main></app-footer-main>
    

    the post talk about separate in diferent files the routes

    0 讨论(0)
  • 2020-12-04 07:01

    You can solve your problem using child routes.

    See working demo at https://angular-multi-layout-example.stackblitz.io/ or edit at https://stackblitz.com/edit/angular-multi-layout-example

    Set your route like below

    const appRoutes: Routes = [
        
        // Site routes goes here 
        { 
            path: '', 
            component: SiteLayoutComponent,
            children: [
              { path: '', component: HomeComponent, pathMatch: 'full'},
              { path: 'about', component: AboutComponent }
            ]
        },
        
        // App routes goes here
        { 
            path: '',
            component: AppLayoutComponent, 
            children: [
              { path: 'dashboard', component: DashboardComponent },
              { path: 'profile', component: ProfileComponent }
            ]
        },
    
        // no layout routes
        { path: 'login', component: LoginComponent},
        { path: 'register', component: RegisterComponent },
        // otherwise redirect to home
        { path: '**', redirectTo: '' }
    ];
    
    export const routing = RouterModule.forRoot(appRoutes);
    
    0 讨论(0)
提交回复
热议问题