Angular 2+ and Ruby on Rails user authentication Part 3

Written by avatsaev | Published 2017/02/09
Tech Story Tags: javascript | angular2 | angular | rails

TLDRvia the TL;DR App

This article is the follow up of Angular 2+ and Ruby on Rails user authentication

App Architecture

Components

  • Home component (Welcome Page)
  • Toolbar component
  • Auth dialog component
  • Login from component
  • Register form component
  • Profile component

Separating Login and Register forms into different components is useful, because we can reuse them in other pages if needed (for example dedicated login and register pages without a dialog)

Routes

  • Home route
  • Profile route

Route Guards

  • Profile route guard: will check if user is logged in, if not, will redirect to home

Services

  • TokenAuthService: will manage login, register, logout, user profile data, verify token authenticity, and check wether the user is logged in or not

Home Component and Home Route

Let’s start by generating our first component, Home, with Angular CLI:

$ ng g c home

g = generate and c = component

This will create ./src/app/home folder with home component class, its template and stylesheet, Angular CLI will also add it to Main App Module’s declarations array automatically.

Now we need to create a route for it, open ./src/app/app-routing.module.ts

Import the HomeComponent:

import {HomeComponent} from "./home/home.component";

and add home route to routes array:

const routes: Routes = [{path: '',children: []},{path: 'home',component: HomeComponent}];

We’ll also make it the default route:

const routes: Routes = [{path: '',component: HomeComponent,pathMatch: 'full'},{path: 'home',component: HomeComponent}];

Now if we go to http://localhost:4200 HomeComponent will be displayed by default

Toolbar Component

Same procedure for Toolbar Component:

$ ng g c toolbar

Setup toolbar’s html template:

For now we’ll display all actions, we’ll implement the conditional state later.

Change ./src/app/home/home.component.html to something more appealing:

Edit ./src/app/app.component.html as follows to display our toolbar and wrap the router outlet in container class:

And here’s what we get so far:

Auth Dialog

Now we need to create the AuthDialogComponent which will display Login/Register forms:

$ ng g c auth-dialog

Let’s edit the AuthDialogComponent file in ./src/app/auth-dialog/auth-dialog.component.ts

Auth Dialog Component will have an Input decorator (line 11) authMode, it takes 2 possible values, ‘login’ or ‘register’, this will allow us to pick the initial form to display when the dialog shows up (login or register form). The default value of this input is ‘login’.

modalActions (line 12) is an event emitter, required by Materialize Dialog Directive, we’ll emit events on it to open or close our dialog.

openDialog (line 18) method takes a mode as its parameter, will set the current auth mode and display the dialog, if no parameter is passed, login will be the default.

isLoginMode and isRegisterMode methods will help us to display the login or register forms conditionally.

Edit this dialog’s template, ./src/app/auth-dialog/auth-dialog.component.html:

On line 2, we are using materialize modal directive, and passing modalActions event emitter for its materializeActions input to be able to control the dialog by emitting events on it.

For now all this dialog is displaying is its current mode on line 17, and the ability to switch modes on lines 23 and 26. The *ngIf structural directive takes a boolean expression, if the expression is true, it will display the node, or hide it otherwise (remove it from the DOM).

Let’s display this dialog when we click on register or login actions in the toolbar.

In ./src/app/toolbar/toolbar.component.html include the auth-dialog component, and create click events on Login and Register actions to open the Auth Dialog:

#authDialog (line 24) is a reference to the AuthDialogComponent of our ToolbarComponent view, it will allow us to access the AuthDialogComponent class from the ToolbarComponent class.

./src/app/toolbar/toolbar.component.ts:

import {Component, OnInit, ViewChild} from '@angular/core';import {AuthDialogComponent} from "../auth-dialog/auth-dialog.component";

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

@ViewChild('authDialog') authDialog: AuthDialogComponent;

constructor() { }

ngOnInit() {}

presentAuthDialog(mode?: 'login'| 'register'){this.authDialog.openDialog(mode);}

}

ViewChild decorator will reference the AuthDialogComponent from our template so we can access its methods and attributes directly from our ToolbarComponent class.

presentAuthDialog method takes an optional mode parameter (notice the question mark), AuthDialogComponenet’s openDialog method defaults the mode to ‘login’, so if we want to open the login dialog, we can just call presentAuthDialog() without any params.

So this is what we get for the Auth Dialog so far:

We’ll use the Token Service to display the correct actions in the toolbar depending on wether or not the user is authenticated, for that, we can use the userSignedIn() method which returns true of the user is logged in.

Import and inject Angular2TokenService into our ToolbarComponent:

Now we can use it on our toolbar template to hide/show actions conditionally, we’ll also attach the signOut method to its action:

Login & Register forms

We’re almost finished. Let’s generate login and register form components.

$ ng g c login-form

$ ng g c register-form

Login form template

We have two text inputs (email & password) both of which are required for form to have a valid state. We are using Angular’s two way data binding on line 12 and 24 to bind the input values to signInUser object in our component class, which means the values will be updated when they are modified in the HTML form by the user, and also updated in the view if they are modified programatically in the component class.

Submit button (line 31) will be in disabled state unless the form becomes valid (line 32).

Login form component

Login form will have an output onFormResult (line 16), which is an event fired when login request completes, so the parent components can listen and act on it.

We’ll inject the Token Service into our component (line 17) and use its signIn method when the form is submitted. When the login action completes, we’ll emit an event on onFormResult output, with a payload containing the result (lines 31 and 37), this will notify the parent components.

Register form template

Pretty similar to login from, but have have an additional password confirmation text field and its validation.

Register form component

Similar to login form, register form has an Output event emitter, onFormResult, that fires when register request completes.

Hooking up the outputs in auth dialog

In the auth dialog component class, create the event handlers for onFormResult events emitted by login and register form components, if the the login/register was successful, close the dialog, otherwise display the error returned by our RoR server in an alert window:

Final Auth Dialog

Notice the toolbar actions updating their state automatically when user logs in and out.

Final source code for this part is available on Github: https://github.com/avatsaev/angular-token-auth-seed/tree/final

Part 4: User Profile, Auth Service and Auth Router Guard.


Published by HackerNoon on 2017/02/09