Twitter LogoFacebook Logo
Project 1: Building a Social Media Site Part 3: Authenticator
The focus in this tutorial is to create the authenticator component so we can reset, create, and log in with an account.
By: King

The Authenticator component will be a pop up window at the bottom of the webpage. When the Get Started or Login button is clicked on, it will slide up. When we click outside of the component, it will slide down to hide itself.

Image from Codeible.com

There is a section for us to reset our password, create an account, and log in. 

The Angular Material UI Components that I am using for this are Button, Bottom Sheet, and Card.

Adding Material UI Component Modules

Go into the app module file and add the MatBottomSheet and MatCard modules to your project. Add the import statements and add it to the app.

...

import { MatButtonModule } from '@angular/material/button';
import { MatBottomSheetModule } from '@angular/material/bottom-sheet';
import { MatCardModule } from '@angular/material/card';


@NgModule({
  declarations: [
    AppComponent,
    ...
  ],
  imports: [
    ...
    MatButtonModule,
    MatBottomSheetModule,
    MatCardModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { 
  constructor(){
    FirebaseTSApp.init(environment.firebaseConfig);
  }
}

Save the project and have the project opened in the browser from where we left off in the previous video.

Creating the Authenticator Component

To begin, create a new component call Authenticator using the ng generate component command and place it in the tools directory.

ng generate component tools/Authenticator

Go into the Home Component HTML page and add a click event to the Get Started button. We want to use this button to trigger the Bottom Sheet.

Home Component HTML

<div id="home-page">
    <div id="home-page-landing">
        <div id="landing-left">
            <div id="landing-left-content">
                <h1>Social Media App Platform</h1>
                <p>
                    Share your favorite stories! #Codeible
                </p>
                <button (click)="onGetStartedClick()"
                mat-flat-button color="warn">Get Started</button>
            </div>
        </div>
        <div>

        </div>
    </div>
</div>

Go into the Home Component TypeScript file and define the click function for the Get Started button. Then import the  MatBottomSheet class from Angular Material and inject it into the constructor. 

...
import { MatBottomSheet } from '@angular/material/bottom-sheet';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {

  constructor(private loginSheet: MatBottomSheet) { }

  ngOnInit(): void {
  }

  onGetStartedClick(){

  }

}

With the bottom sheet object, we can trigger and open the bottom sheet. 

Go into the onGetStartedClick() function, grab the Bottom Sheet object, call the open method, and pass in the Authenticator component.

onGetStartedClick(){

    this.loginSheet.open(AuthenticatorComponent);

}

When we run the app on the browser and click on the Get Started button, the Bottom Sheet will show.

Adding Trigger to Login Navigation Item

Next, do the same for the Navbar. Go into the App Component HTML page and attach a click event for the login navigation item. Then go into the App Component TypeScript file to define the function.

App Component HTML

<div id="nav-bar">
    <div id="nav-bar-content">
        <div id="nav-bar-left">
            <div style="font-size: 1.5em;" class="nav-bar-items">Codeible</div>
        </div>
        <div id="nav-bar-right">
            <div (click)="onLoginClick()" 
            class="nav-bar-items">Login</div>
        </div>
    </div>
</div>

App Component TypeScript

...

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  ...

  constructor(){

  }

  onLoginClick(){

  }

}

Import and inject MatBottomSheet and then call the open method in the onLoginClick() function.

import { MatBottomSheet } from '@angular/material/bottom-sheet';
import { AuthenticatorComponent } from './tools/authenticator/authenticator.component';


@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  ...

  constructor(private loginSheet: MatBottomSheet){

  }

  onLoginClick(){
      this.loginSheet.open(AuthenticatorComponent);
  }

}

If we go to our app and click on the Login button, the bottom sheet will also show.

Adding Contents to Bottom Sheet

The next step is to the define the contents inside the Bottom Sheet for the Authenticator. Go to the Authenticator component HTML page and remove the default code.


1) Add a div element and give it an id call authenticator
2) Inside the authenticator div, add the Card Component. Use the mat-card element to create the card container and give it an id call authenticator-content.

<div id="authenticator">
    <mat-card id="authenticator-content">

    </mat-card>
</div>

There are 3 sections to the card component, the header, the content area, and the actions bar. 


To add the header, use the mat-card-header element and inside it, use the mat-card-title element to define the tile.

For the content, add a div element underneath the header element. Put 2 inputs and a button inside.  

1) For the button style, apply the mat-flat-button property and set the color to warn. 
2) For the password input, set the type to password.

<mat-card id="authenticator-content">
        <mat-card-header>
            <mat-card-title>Login</mat-card-title>
        </mat-card-header>
        <div >
            <input placeholder="Email"/>
            <input placeholder="Password" type="password">
            <button mat-flat-button color="warn">Login</button>
        </div>
<mat-card>

For the action bar, use the mat-card-actions element and set the align attribute to end. This will align all the contents inside the bar to the right. 

Lastly, place 3 buttons inside the action bar:

One for Forgot Password
One for Create an account
One for Log in 

Use the mat-flat-button styles for all 3.

<mat-card id="authenticator-content">
        <mat-card-header>
            ...
        </mat-card-header>
        <div >
            ...
        </div>

        <mat-card-actions align="end">
            <button mat-flat-button>Forgot Password</button>
            <button mat-flat-button>Create an Account</button>
            <button mat-flat-button>Login</button>
        </mat-card-actions>
<mat-card>

If we turn to our app, we should have a card component inside the bottom sheet with the contents

Image from Codeible.com

Styling the Contents

Go to the Authenticator Component CSS file and add the selectors for authenticator and authenticator-content.

For authenticator, use:

#authenticator {
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 1em;
    box-sizing: border-box;
    -moz-box-sizing: border-box;
    -webkit-box-sizing: border-box;
}

For authenticator-content, use:

#authenticator-content {
    width: 100%;
    max-width: 30em;
    padding: 1.5em;
}

Lastly add the styles for the inputs and buttons. 

button {
    margin: .5em;
}

input {
    width: 100%;
    padding: 1em;
    margin: .5em 0;
    border-radius: 5px;
    outline: none;
    border: 1px solid rgba(15, 15, 15, .3);
    box-sizing: border-box;
    -moz-box-sizing: border-box;
    -webkit-box-sizing: border-box;
}

Image from Codeible.com

As you can see our styles are complete. We just need to add functionality to the buttons to change the content based on which one is clicked on.

Adding the Register and Reset Password Contents

Go to the Authenticator Component HTML page. Since we have the contents for log in, we just need to add the contents for Creating an Account and Resetting the password.


1) Add 2 more div elements inside the card component.
2) For the first div, add 3 inputs and a button. This will be the content for registering for an account.
3) For the second div, add 1 input and a button. This will be the content for resetting our password.

<mat-card id="authenticator-content">
        <mat-card-header>
            ...
        </mat-card-header>
        <div >
            <input placeholder="Email"/>
            <input placeholder="Password" type="password">
            <button mat-flat-button color="warn">Login</button>
        </div>
        <div >
            <input placeholder="Email"/>
            <input placeholder="Password">
            <input placeholder="Confirm Password">
            <button mat-flat-button color="warn">Register</button>
        </div>

        <div >
            <input placeholder="Email"/>
            <button mat-flat-button color="warn">Reset</button>
        </div>

        <mat-card-actions align="end">
            <button mat-flat-button>Forgot Password</button>
            <button mat-flat-button>Create an Account</button>
            <button mat-flat-button>Login</button>
        </mat-card-actions>
<mat-card>

Do not forget to set the type of the password inputs to password.

<input placeholder="Password" type="password">
<input placeholder="Confirm Password" type="password">

If we go to our app, all 3 contents will be stacked on top of each other which is what we want for now.

Image from Codeible.com

Go back to the Authenticator Component HTML page and add a click event to each button in the action bar. Then define the functions in the TypeScript file.

Authenticator Component HTML

<mat-card-actions align="end">
      <button mat-flat-button
           (click)="onForgotPasswordClick()">Forgot Password</button>
      <button mat-flat-button
           (click)="onCreateAccountClick()">Create an Account</button>
      <button mat-flat-button
           (click)="onLoginClick()">Login</button>
</mat-card-actions>

Authenticator Component TypeScript

onForgotPasswordClick(){

}

onCreateAccountClick(){

}

onLoginClick(){

}

Scroll to the bottom of the component and define an enum call AuthenticatorComponentState. This enum will have 3 values, LOGIN, REGISTER, and FORGOT_PASSWORD.

export enum AuthenticatorCompState {
  LOGIN,
  REGISTER,
  FORGOT_PASSWORD
}

1) Inside the Authenticator component, declare variable for the enum and set it to LOGIN.
2) Go to the onForgotPasswordStateClick() function and set the state to FORGOT_PASSWORD 
3) For OnCreateAccountStateClick(), set it to REGISTER.
4) And For onLoginStateClick(), set it to LOGIN.

...
state = AuthenticatorCompState.LOGIN;

constructor() { 
   ...
}

onForgotPasswordClick(){
    this.state = AuthenticatorCompState.FORGOT_PASSWORD;
}

onCreateAccountClick(){
    this.state = AuthenticatorCompState.REGISTER;
}

onLoginClick(){
    this.state = AuthenticatorCompState.LOGIN;
}

With this, we can toggle which content we want to display using the *ngIf directive. 

Define 3 more function:

1) isLoginStatte()
2) isRegisterState()
3) isForgotPasswordSate().

For isLoginState(), we want to check if the state is LOGIN.
For isRegisterState(), we want to check if the state is REGISTER.
And For isForgotPasswordState(), we want to check if the state is FORGOT_PASSWORD.

isLoginState(){
    return this.state == AuthenticatorCompState.LOGIN;
}

isRegisterState(){
    return this.state == AuthenticatorCompState.REGISTER;
}

isForgotPasswordState(){
    return this.state == AuthenticatorCompState.FORGOT_PASSWORD;
}

Go to the Authenticator Component HTML page and use the *ngIf directive to display each content.

1) For the log in content, check if it is login state
2) For the register content, check if it is register state
3) And for the reset password content, check if it is forgot password state

<mat-card id="authenticator-content">
        <mat-card-header>
            <mat-card-title>Login</mat-card-title>
        </mat-card-header>

        <div *ngIf="isLoginState()" >
            <input placeholder="Email"/>
            <input placeholder="Passwordtype="password">
            <button mat-flat-button color="warn">Login</button>
        </div>
        <div *ngIf="isRegisterState()">
            <input placeholder="Email"/>
            <input placeholder="Password">
            <input placeholder="Confirm Password">
            <button mat-flat-button color="warn">Register</button>
        </div>
        <div *ngIf="isForgotPasswordState()">
            <input placeholder="Email"/>
            <button mat-flat-button color="warn">Reset</button>
        </div>

<mat-card>

If we go to our app, we should be able to toggle between the 3 contents.

Changing the Header

There is one more thing that we are missing. The header is staying the same. 


Go to the Authenticator Component TypeScript file and use the same concept to get the text for each state.

Define a function call getStateText(). Inside the function, use a switch case to determine which text you want to display.

getStateText(){
    switch(this.state){
      case AuthenticatorCompState.LOGIN:
        return "Login";
      case AuthenticatorCompState.REGISTER:
        return "Register";
      case AuthenticatorCompState.FORGOT_PASSWORD:
        return "Forgot Password";
    }
}

Go back to the Authenticator Component HTML page  and use interpolation to get the text.

<mat-card-header>
      <mat-card-title>{{getStateText()}}</mat-card-title>
</mat-card-header>

This will change the text depending on the content that is displayed.


Sign In