问题
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:
- Login, register page (no header, no footer)
routes: ['login','register']
- Marketing site page (this is the root path and it has a header and footer, mostly these sections come before login)
routes : ['','about','contact']
- App logged in pages (I have a different header and footer in this section for all the app pages but this header and footer is different from the marketing site header and footer)
routes : ['dashboard','profile']
I run the app temporarily by adding a header and footer to my router component html.
Please advise me a better approach.
This is my code:
app\app.routing.ts
const appRoutes: Routes = [
{ path: '', component: HomeComponent},
{ path: 'about', component: AboutComponent},
{ path: 'contact', component: ContactComponent},
{ path: 'login', component: LoginComponent },
{ path: 'register', component: RegisterComponent },
{ path: 'dashboard', component: DashboardComponent },
{ path: 'profile', component: ProfileComponent },
// otherwise redirect to home
{ path: '**', redirectTo: '' }
];
export const routing = RouterModule.forRoot(appRoutes);
app.component.html
<router-outlet></router-outlet>
app/home/home.component.html
<site-header></site-header>
<div class="container">
<p>Here goes my home html</p>
</div>
<site-footer></site-footer>
app/about/about.component.html
<site-header></site-header>
<div class="container">
<p>Here goes my about html</p>
</div>
<site-footer></site-footer>
app/login/login.component.html
<div class="login-container">
<p>Here goes my login html</p>
</div>
app/dashboard/dashboard.component.html
<app-header></app-header>
<div class="container">
<p>Here goes my dashboard html</p>
</div>
<app-footer></app-footer>
I saw this question on stack-overflow but i didn't get a clear picture from that answer
回答1:
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 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);
回答2:
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
回答3:
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:
<app-header-main [showUserTools]="false"></app-header-main>
or
<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
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>
回答4:
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';
}
}
来源:https://stackoverflow.com/questions/46527826/best-method-to-set-different-layout-for-different-pages-in-angular-4