Multiple layouts for different pages in Angular 2

Angular

Angular Problem Overview


I have a login page - just 2 input (no header, no footer, no sidebar)

When a user signs in he should be navigated to a page with header, footer and right navbar.

the only thing that changes on the inner page is the right side content.

import { Component } from '@angular/core';
import { ViewEncapsulation } from '@angular/core';

@Component({
  selector: 'pm-app',
  template: `
  <div>
      <router-outlet></router-outlet>
   </div>
   `,
   styleUrls:["app/app.component.css"],
    encapsulation: ViewEncapsulation.None
})
export class AppComponent {
  pageTitle: string = 'Acme Product Management';
}

I understand this app.component is like master page where you can add the header and footer and the <router-outlet></router-outlet> is where the content changes based on the routing.

How do I make one layout for the login page and another layout with header, footer and right sidebar for the inside page?

Angular Solutions


Solution 1 - Angular

You could use child routes to use different layouts for different views.

Here is a common example of using child routes in Angular2

I like to use child routes to separate secure pages and unsecure pages in my angular 2 applications.

In my app root I have two directories

/Public

&

 /Secure

Now in the root directory I also have

/app.routing.ts

from there I create a layouts folder,

/layouts

In that directory I create

/layouts/secure.component.ts
/layouts/secure.component.html

&

/layouts/public.component.ts
/layouts/public.component.html

from this point I can divert my routes to one of the two layouts depending if the page is meant to be secure or public. I do this by creating a route to each layout in my root routes.ts file.

/app.routes.ts

const APP_ROUTES: Routes = [
    { path: '', redirectTo: '/home', pathMatch: 'full', },
    { path: '', component: PublicComponent, data: { title: 'Public Views' }, children: PUBLIC_ROUTES },
    { path: '', component: SecureComponent, canActivate: [Guard], data: { title: 'Secure Views' }, children: SECURE_ROUTES }
];

Notice that I register my child routes for each layout. That is the exported value of each separate route file. One is in the public directory and one is in the secure directory.

/public/public.routes.ts

export const PUBLIC_ROUTES: Routes = [
    { path: '', redirectTo: 'home', pathMatch: 'full' },
    { path: 'p404', component: p404Component },
    { path: 'e500', component: e500Component },
    { path: 'login', component: LoginComponent },
    { path: 'register', component: RegisterComponent },
    { path: 'home', component: HomeComponent },
    { path: 'benefits', component: BenefitsComponent },
    { path: 'services', component: ServicesComponent },
    { path: 'education', component: EducationComponent },
    { path: 'products', component: ProductsComponent },
    { path: 'fcra', component: FcraComponent },
    { path: 'croa', component: CroaComponent },
    { path: 'building', component: BuildingComponent },
    { path: 'tips', component: TipsComponent },
    { path: 'maintenance', component: MaintenanceComponent }
];

All of these routes are now accessible as the child routes for my public layout. Which now leads us to protecting our secure views.

So in the secure directory I essentially do the same thing,

/secure/secure.routes.ts

export const SECURE_ROUTES: Routes = [
    { path: '', redirectTo: 'overview', pathMatch: 'full' },
    { path: 'items', component: ItemsComponent },
    { path: 'overview', component: OverviewComponent },
    { path: 'profile', component: ProfileComponent },
    { path: 'reports', component: ReportsComponent },
    { path: 'recommendations', component: RecommendationsComponent },
    { path: 'score-simulator', component: ScoreSimulatorComponent },
    { path: 'payment-method', component: PaymentMethodComponent },
    { path: 'lock-account', component: LockAccountComponent }
];

This allows me to use auth to protect those child routes now. If you remember in

/app.routes.ts we did this for the secure routes,

{ path: '', component: SecureComponent, canActivate: [Guard], data: { title: 'Secure Views' }, children: SECURE_ROUTES }

Notice the [Guard]. This allows us to protect all of the child routes for the secure layout. This is one reason I use child routes. I could give you a lot more but I feel this is the most reasonable explanation.

Just to take things a small step further and put this in perspective for you this is how I [Guard] the secure pages. Creating a service and implementing CanActivate

@Injectable()
export class Guard implements CanActivate {

    constructor(protected router: Router, protected auth: Auth ) {}

     canActivate() {
        if (localStorage.getItem('access_token')) {
            // logged in so return true
            return true;
        }
        // not logged in so redirect to login page
        this.router.navigate(['/home']);
        return false;
    }
}

This allows you to serve public layout with <router-outlet></router-outlet> then use a different header and footer in the layout. Then use <router-outlet></router-outlet> in the secure layout again and obviously a different header and footer. Let me know if I have left anything unclear and I will update the answer.

Solution 2 - Angular

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);

Solution 3 - Angular

You can have multiple router-outlet and redirect where you want. For example login page can be the landing page if user is not logged in and if use is logged in you redirect user to a master page where you have header and footer and all other pages can be child of that component. For example we have our app like this

<my-app></my-app>

in my-component you have a

<router-outlet></router-outlet> ¨ you have one login component and you can use that routing for that page like this

 { path: '', component: LoginComponent}

as told earlier this can be landing page and you don't want to show anything else then login details. Once user sign in you redirect user to master component and master component will have routing like this

{ path: 'masterpage', component: MasterComponent}

and master component will have router outlet as well

<router-outlet></router-outlet>

now when you want to show user other pages like about us. then you will redirect user to about us page like this

{ canActivate: [AuthGuard], component: MasterComponent , path: 'masterpage',
  children:[
           {   canActivate: [AuthGuard],
               component: AboutUsComponent ,
               path: 'aboutus'
           }]
}

and this way you will have details like header and footer every where use navigate. I hope this helps!

Solution 4 - Angular

Notice the router-outlet. That is where you content will be displayed. This is an example of my app.component.html. In this case the redirect is to the home.component and its displayed in the router outlet.

<div class="ui-grid ui-grid-responsive ui-grid-pad">
	<div class="ui-g borderDiv" [ngStyle]="appPageHeaderDivStyle">
		<div class="ui-g-12" *ngIf="!isLoggedIn">
			<div class="ui-g">
				<div class="ui-xl-2">
					<img class="logo" src="./app/resources/KetoLightLogo.png">
				</div>
				<div class="ui-xl-7">
				</div>
				<div class="ui-xl-3 ui-g-nopad" style="width: 320px; margin-left: 80px; float: right; ">
					<div>
						<p-menubar class="pMenuBar" [model]="items"></p-menubar>
					</div>
				</div>
			</div>
		</div>

		<div class="ui-g-12" *ngIf="isLoggedIn">
			<div class="ui-g">
				<div class="ui-xl-2">
					<img class="logo" src="assets/KetoLightLogo.png">
				</div>
				<div class="ui-xl-4">
					<label class="ui-widget loggedInLabel">Logged in as: [email protected]</label>
				</div>
				<div class="ui-xl-6 ui-g-nopad" style="width: 525px;  margin-left: 270px; float: right; ">
					<p-menubar [model]="items"></p-menubar>
				</div>
			</div>
		</div>
	</div>
</div>

<router-outlet></router-outlet>

<div class="ui-grid ui-grid-responsive ui-grid-pad">
	<div class="ui-g borderDiv" [ngStyle]="appPageHeaderDivStyle">
		<div class="ui-g-12">
			<div class="ui-g">
				<div class="ui-g-12 ui-md-12 ui-lg-12">
					<div class="ui-g-row">
						<div class="ui-g-12">
							<div class="ui-g-12 ui-md-12 ui-lg-12">
								<div class="ui-g-1 ui-md-4 ui-lg-5">
								</div>
								<div class="ui-g-10 ui-md-4 ui-lg-2">
									<p class="copyright">Copyright 2016 Xamlware, Inc.</p>
									<p class="copyright2">All rights reserved</p>
								</div>
								<div class="ui-g-1 ui-md-4 ui-lg-5">
								</div>
							</div>
						</div>
					</div>
				</div>
			</div>
		</div>
	</div>
</div>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionbaarozView Question on Stackoverflow
Solution 1 - AngularwunoView Answer on Stackoverflow
Solution 2 - AngularRameez RamiView Answer on Stackoverflow
Solution 3 - AngularJorawar SinghView Answer on Stackoverflow
Solution 4 - AngularJohn BairdView Answer on Stackoverflow