[转]Angular: Hide Navbar Menu from Login page
本文转自:https://loiane.com/2017/08/angular-hide-navbar-login-page/
In this article we will learn two approaches to hide the Navbar Menu when displaying the Login page in Angular projects.
Update December 2017: code updated to Angular v5 and Material v5.
Update May 2018: code updated to Angular v6. Stackblitz link also available at the end of this article.
Contents
For both examples in this tutorial we will use Angular Material as our UI library. I’ve covered how to setup an Angular project with Angular Material in this post.
Example 1: Using *ngIf to “hide” the NavBar
In this first example we will have only one page layout and we will verify if the user is logged in and use *ngIf to verify if the application should display the navigation bar or not. This is the most common example we find when searching for how to hide the navbar when displaying the login page.
So let’s start creating our first example with Angular CLI:
ng new angular-login-hide-navbar-ngif --routing --style=scss
For this example we will need to create some components, a module, a service, a route guard and a model interface:
ng g m app-material
ng g s auth/auth --module=app.module
ng g g auth/auth --module=app.module
ng g i auth/user
ng g c header -is
ng g c home -is -it
ng g c login
With the commands above all components and services will be created and the declarations and providers metadata of app.module.ts will also be updated.
Don’t forget to setup the CSS framework or UI library for your project as well!
The image below shows the project src folder for this first example and also for our second example. Both examples use basically the same components, however, the second example has two extra components.

The application shall display the navigation bar only when the user is logged in as demonstrated by the following screenshot:

The toolbar from the screenshot above is displaying both Login and Logout buttons. But we’ll get there to fix this later.
If the user is not logged in, the application shall display the login page without the navigation bar as demonstrated below:

Ok, we have our requirenments, let’s start coding!
The app-material module
To develop this simple application, we will need some UI components. Since we are using Angular Material, we will need the following Material modules to be imported by our application:
import { NgModule } from '@angular/core';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatCardModule } from '@angular/material/card';
import { MatButtonModule } from '@angular/material/button';
import { MatInputModule } from '@angular/material/input';
import { MatFormFieldModule } from '@angular/material/form-field';
@NgModule({
exports: [
MatToolbarModule,
MatCardModule,
MatInputModule,
MatFormFieldModule,
MatButtonModule
]
})
export class AppMaterialModule {}
We cannot forget to update our app.module.ts and import AppMaterialModule.
In your application, import the
AppMaterialModulein all modules that your components belongs to. Since this is a very small project, we only have one module with components which is the app.module.
Since we imported MatInputModule, this means we will work with forms. So we also need to import ReactiveFormsModule (or FormsModule if you prefer to work with template driven forms):
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ReactiveFormsModule } from '@angular/forms';
import { AppMaterialModule } from './app-material/app-material.module';
@NgModule({
// ...
imports: [
// ...
ReactiveFormsModule,
BrowserAnimationsModule,
AppMaterialModule
],
// ...
})
export class AppModule { }
Creating the Login component
The code for the login.component.ts is presented below:
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { AuthService } from './../auth/auth.service';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.scss']
})
export class LoginComponent implements OnInit {
form: FormGroup; // {1}
private formSubmitAttempt: boolean; // {2}
constructor(
private fb: FormBuilder, // {3}
private authService: AuthService // {4}
) {}
ngOnInit() {
this.form = this.fb.group({ // {5}
userName: ['', Validators.required],
password: ['', Validators.required]
});
}
isFieldInvalid(field: string) { // {6}
return (
(!this.form.get(field).valid && this.form.get(field).touched) ||
(this.form.get(field).untouched && this.formSubmitAttempt)
);
}
onSubmit() {
if (this.form.valid) {
this.authService.login(this.form.value); // {7}
}
this.formSubmitAttempt = true; // {8}
}
}
Our login screen is going to be a simple form with two fields: user name and password and they are both required ({5}). So first we need to declare a form variable ({1}). I like to use the FormBuilder instead of instantiating each FormGroup and FormControl, so in this case we also need to inject it in our component’s contructor ({3}).
Since we are in the constructor, when the user clicks on the login button and the form is valid, we will submit its values ({7}) to the AuthService that will be responsible for the login logic. So we also need to inject it in the component’s contructor ({4}). This service was declared as provider in the app.module when we used the ng g s auth/auth --module command.
To display some validation error messages in our form, we’ll verify if the field is invalid or has been touched (received focus) ({6}). We’ll also be using the submit attempt flag approach ({2} and {8}).
To learn more about the submit attempt flag approach you can read this tutorial.
Our form will use some custom CSS styles as well:
mat-card {
max-width: 400px;
margin: 2em auto;
text-align: center;
}
.signin-content {
padding: 60px 1rem;
}
.full-width-input {
width: 100%;
}
And now that we have the Angular form in place, let’s take a look at the login template built with Angular Material:
<div class="signin-content">
<mat-card>
<mat-card-content>
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<p>Please login to continue</p>
<mat-form-field class="full-width-input">
<input matInput placeholder="User" formControlName="userName" required>
<mat-error *ngIf="isFieldInvalid('userName')">
Please inform your user name
</mat-error>
</mat-form-field>
<mat-form-field class="full-width-input">
<input matInput type="password" placeholder="Password" formControlName="password" required>
<mat-error *ngIf="isFieldInvalid('userName')">
Please inform your password
</mat-error>
</mat-form-field>
<button mat-raised-button color="primary">Login</button>
</form>
</mat-card-content>
</mat-card>
</div>
Our login widget is a Material card with maximum width of 400 pixels, with two required form fields and a login button.
Creating the Home component
Our Home component is going to be very simple. Just a message confirming the user is logged in:
import { Component } from '@angular/core';
@Component({
selector: 'app-home',
template: '<p>Yay! You are logged in!</p>',
styles: []
})
export class HomeComponent {}
Creating the AuthService
For the purpose of this example, we will not integrate the service with any backend API.
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { BehaviorSubject } from 'rxjs';
import { User } from './user';
@Injectable()
export class AuthService {
private loggedIn = new BehaviorSubject<boolean>(false); // {1}
get isLoggedIn() {
return this.loggedIn.asObservable(); // {2}
}
constructor(
private router: Router
) {}
login(user: User){
if (user.userName !== '' && user.password !== '' ) { // {3}
this.loggedIn.next(true);
this.router.navigate(['/']);
}
}
logout() { // {4}
this.loggedIn.next(false);
this.router.navigate(['/login']);
}
}
To control if the user is logged in or not, we will use a BehaviorSubject ({1}). We will also create a getter to expose only the get method publicly ({2}) as also expose the Subject as an Observable. The BehaviorSubject keeps the latest value cached (in our case when the service is created the initial value is going to be false). So when an Observer subscribes to the isLoggedIn(), the cached valued is going to be emitted right away.
When the user clicks on the login button from the form, the login method is going to be called receiving the form values. Our validation is very simple: we are only checking if the values are not empty (of course the best behavior here is to submit the values to a server and maybe also use JWT). If we received a userName and a password ({3}), then we authenticate the user. This means we need to emit that the user is now logged in and also redirect the routing to the HomeComponent.
And in case the user logs out of the application ({3}4, we will emit that the user is no longer logged in and also redirect to the login page.
The User interface matches the FormControl names from our LoginComponent form:
export interface User {
userName: string;
password: string;
}
Configuring the Router and the AuthGuard
These will be the routes we will use in this example:
const routes: Routes = [
{ path: '', component: HomeComponent, canActivate: [AuthGuard] },
{ path: 'login', component: LoginComponent }
];
Now let’s take a look the auth/auth.guard:
import { Injectable } from '@angular/core';
import {
ActivatedRouteSnapshot,
CanActivate,
Router,
RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs';
import { map, take } from 'rxjs/operators';
import { AuthService } from './auth.service';
@Injectable()
export class AuthGuard implements CanActivate {
constructor(
private authService: AuthService,
private router: Router
) {}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean> {
return this.authService.isLoggedIn // {1}
.pipe(
take(1), // {2}
map((isLoggedIn: boolean) => { // {3}
if (!isLoggedIn){
this.router.navigate(['/login']); // {4}
return false;
}
return true;
});
)
}
}
First we are going to retrieve the isLoggedIn ({1}) getter from the AuthService, which is an Observable. Since we are only interested in checking the value from the Observalbe a single time (if the user is logged in or not), we will use the take operator ({2}). We will verify the value emitted by the BehaviorSubject ({3}) and if not logged in we will navigate to the login screen ({4}) and return false. The AuthGuard will return true in case the user is logged in, meaning the user can access the route (path: ‘’) which renders the HomeComponent.
Updating the AppComponent
For this example, we AppComponent will be our main component:
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: `
<app-header></app-header>
<router-outlet></router-outlet>
`,
styles: []
})
export class AppComponent {}
It will display the app-header which is our navigation bar and the component according to the routing config.
Creating the Navigation Bar
Let’s start creating the navigation bar with the simplest template:
<mat-toolbar color="primary">
<span>
<img src="assets/img/angular_whiteTransparent.svg" class="angular-logo">
Angular NavBar + Login Example #01
</span>
<span class="fill-remaining-space"></span>
<button mat-button>Menu Option 01</button>
<button mat-button>Menu Option 02</button>
<button mat-button routerLink="login">Login</button>
<button mat-button (click)="onLogout()">Logout</button>
</mat-toolbar>
Our navbar has a title, two menu options (just to look prettier) and a Login + Logout buttons.
If try to execute the application now (ng serve) and access the /login route we will have the following result:

We still need to hide the navigation bar.
So let’s implement the required logic in the header.component:
import { Observable } from 'rxjs/Observable';
import { AuthService } from './../auth/auth.service';
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styles: [
`.angular-logo {
margin: 0 4px 3px 0;
height: 35px;
vertical-align: middle;
}
.fill-remaining-space {
flex: 1 1 auto;
}
`
]
})
export class HeaderComponent implements OnInit {
isLoggedIn$: Observable<boolean>; // {1}
constructor(private authService: AuthService) { }
ngOnInit() {
this.isLoggedIn$ = this.authService.isLoggedIn; // {2}
}
onLogout(){
this.authService.logout(); // {3}
}
}
First, we will declare an Observable ({1}) to receive the value emitted from the AuthService ({2}). We are using $ at the end of the Observable identifier. This helps us while reading the code to identify which variables are Observables or not.
We will not subscribe to the Observable in the HeaderComponent TypeScript code. We will only store the Observable reference (
{2}). We will use theasyncpipe in the HTML template to subscribe/unsubscribe to/from the Observable automatically. This is considered a best practice by the Angular/RxJS community.
And at last, when the user clicks on the logout we will call the logout method ({3}) from the AuthService.
So now let’s back to the HTML template and use *ngIf to display the navbar or not:
<mat-toolbar color="primary" *ngIf="isLoggedIn$ | async">
The code above is enough to display or not the navbar.
The *ngIf does not show or hide the DOM element, it creates (show) or destroys it. We could also use the hidden HTML property, but in this case, if the user does not have access to the application, it is better to not create the DOM Element for security purposes instead of only hiding it.
Just for the purpose of this example, suppose we also want to verify if the user is logged in and display the Logout button:
<button mat-button (click)="onLogout()" *ngIf="isLoggedIn$ | async">Logout</button>
Note that the expression is the same as used in the navbar. We are subscribing to the isLoggedIn$ twice. We can write a better code and only subscribe once by using the as alias introduced in Angular v4.0 enhanced *ngIf and *ngFor:
<mat-toolbar color="primary" *ngIf="isLoggedIn$ | async as isLoggedIn">
<!-- more HTML template code -->
<button mat-button (click)="onLogout()" *ngIf="isLoggedIn">Logout</button>
</mat-toolbar>
The code above means we are subscribing to the isLoggedIn$ and storing its value in the isLoggedIn local template variable. Then we can use this variable in other parts of the template such as the Logout button!
Now we have the expected behavior for our example:

Example 2: Using different layouts and routing config
For the second example the code is basically the same as the example 1, but with a few changes. Instead of using *ngIf to hide the navbar, we are going to use different page layouts with child routes. All the control will be in the routing config.
The first change is regarding the home.component. We do not need the conditional *ngIf="isLoggedIn$ | async as isLoggedIn" to “hide” the navbar.
We also need to create two new components:
ng g c layouts/home-layout -is -it
ng g c layouts/login-layout -is -it
Creating the HomeLayout page
For the HomeLayout, we want to display the navbar, so our component will have the following code:
import { Component } from '@angular/core';
@Component({
selector: 'app-home-layout',
template: `
<app-header></app-header>
<router-outlet></router-outlet>
`,
styles: []
})
export class HomeLayoutComponent {}
Creating the LoginLayout page
For the LoginLayout, we do not want to display the navbar, so our component will have the following code:
```jsimport { Component, OnInit } from ‘@angular/core’;
@Component({ selector: ‘app-login-layout’, template: ` `, styles: [] }) export class LoginLayoutComponent {}
The component only has the `router-outlet` to display the LoginComponent.
### Configuring the routes and child routes
Our routing config will be different from the first example:
```js
const routes: Routes = [
{
path: '', // {1}
component: HomeLayoutComponent,
canActivate: [AuthGuard], // {2}
children: [
{
path: '',
component: HomeComponent // {3}
}
]
},
{
path: '',
component: LoginLayoutComponent, // {4}
children: [
{
path: 'login',
component: LoginComponent // {5}
}
]
}
];
When we try to access "htpp://localhost:4200/", Angular will evaluate the route paths. The first part of the path for the first route configured is "" ({1}), so let’s continue evaluating the second part which is also "" ({2}), so we have a match! But the guard ({3}) still need to verify if the user can access the HomeLayoutComponent (if user is logged in). If the user is logged in, then the access is granted and the user will see the HomeLayoutComponent (the navbar along with the HomeComponent being rendered in the router-outlet), otherwise it is redirected to "htpp://localhost:4200/login".
So suppose we are trying to access "htpp://localhost:4200/login". Angular will evaluate the route path again. The first part of the path for the first route configured is "" ({1}), so let’s continue evaluating the second part which is "login", so we do not have a match with ({3}). We need to evaluate the next route configured. Let’s go again! The first part of the path for the first route configured is "" ({4} this time), so let’s continue evaluating the second part which is "login" and we have a match ({5}). In this case the LoginLayoutComponent is displayed. Since there is only a router-outlet in the HTML template, only the LoginComponent will be displayed.
And we have the same output as the example 1!
This approach where we control the layouts using the router configuration can be used in applications that have different page layouts such as a plain page, or a page with a header navbar, or a page with a sidebar (very used in admin layouts).
Source code + Stackblitz
Source code available on GitHub
References:
Happy coding!
[转]Angular: Hide Navbar Menu from Login page的更多相关文章
- gitlab手残点错关闭注册No authentication methods configured on login page
Gitlab - 如何解決 "No authentication methods configured on login page" ? (gitlab version : 8.1 ...
- react login page demo
1. login form import React from "react"; import {Row, Col} from "antd"; import { ...
- google login page
</pre><pre name="code" class="html"><div class="container&qu ...
- <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Login.aspx.cs" Inherits="Login" %>
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Login.aspx.cs&qu ...
- Page Security
参见开发文档 Overview This document describes how to build applications that grant selected access to indi ...
- Page Object Model (Selenium, Python)
时间 2015-06-15 00:11:56 Qxf2 blog 原文 http://qxf2.com/blog/page-object-model-selenium-python/ 主题 Sel ...
- 无废话网页重构系列——(6)HTML主干结构:站点(site)、页面(page)
本文作者:大象本文地址:http://www.cnblogs.com/daxiang/p/4653546.html 在分析和切出设计稿,以及部署项目目录文件后,开始写HTML Demo. 首先,弄出H ...
- Angular 2.0 从0到1 (六)
第一节:Angular 2.0 从0到1 (一)第二节:Angular 2.0 从0到1 (二)第三节:Angular 2.0 从0到1 (三)第四节:Angular 2.0 从0到1 (四)第五节: ...
- Angular 2 从0到1 (三)
作者:王芃 wpcfan@gmail.com 第一节:Angular 2.0 从0到1 (一)第二节:Angular 2.0 从0到1 (二)第三节:Angular 2.0 从0到1 (三)第四节:A ...
随机推荐
- ireport图形化界面生成pdf文档
一.ireport软件安装 1.下载软件的官网 https://community.jaspersoft.com/project/ireport-designer/releases 2.安装软件 ...
- 【repost】javascript callback
在javascript中回调函数非常重要,它们几乎无处不在.像其他更加传统的编程语言都有回调函数概念,但是非常奇怪的是,完完整整谈论回调函数的在线教程比较少,倒是有一堆关于call()和apply() ...
- Java中的==与equals
当使用==操作符判断类时,实际上判断的是二者是否指向同一个对象 若要判断两个对象是否含有相同的数据,需使用Object类中的equals方法 java中所有类都是从Object类中派生出来的
- python多线程在渗透测试中的应用
难易程度:★★★ 阅读点:python;web安全; 文章作者:xiaoye 文章来源:i春秋 关键字:网络渗透技术 前言 python是门简单易学的语言,强大的第三方库让我们在编程中事半功倍,今天, ...
- Tomcat 的 ManagerApp 简单使用
当启动Tomcat的时候,直接访问http://localhost:8080会直接进入下面页面,原因是Tomcat的默认项目是部署在webapps目录下的ROOT目录下的,这个manager项目就在R ...
- Kali学习笔记29:默认安装漏洞
文章的格式也许不是很好看,也没有什么合理的顺序 完全是想到什么写一些什么,但各个方面都涵盖到了 能耐下心看的朋友欢迎一起学习,大牛和杠精们请绕道 默认安装漏洞: 早期Windows默认自动开启很多服务 ...
- 常见的anaconda的操作
以前对anaconda的理解比较少,以为它就是一个比较大的python库,现在发现它原来不止是这样,它还有很多其他用途. Anaconda指的是一个开源的Python发行版本,其包含了conda.Py ...
- Python 音视频方面资源大全
自然语言处理 用来处理人类语言的库. NLTK:一个先进的平台,用以构建处理人类语言数据的 Python 程序.官网 jieba:中文分词工具.官网 langid.py:独立的语言识别系统.官网 Pa ...
- Kubernetes 新时代的宠儿
本文首发于我的公众号 Linux云计算网络(id: cloud_dev),专注于干货分享,号内有 10T 书籍和视频资源,后台回复「1024」即可领取,欢迎大家关注,二维码文末可以扫. Kuberne ...
- 工作随笔—integer对象比较
问题:对于integer对象,当比较2==2的时候,返回的值是true还是false?当比较2000==2000的时候,返回的值是true还是false? 回答:当比较2==2的时候,返回的值是tru ...