Angular Login & Register with PHP & MYSQL

This is the second part of Angular tutorials. In the first part, you learnt to create Angular app and add a side bar menu. In the second part, you learn to create register and login forms and access PHP APIs using Angular services. 

Execute the following commands to generate register and login components.


ang14-client>ng generate component register

ang14-client>ng generate component login


The register and components are created in register and login folders. In Angular, a component relies on a service to work with  APIs to access data from a database. Let execute the command below to generate auth service in services folder.

ang14-client>ng generate service services/auth

register/register.component.ts

import { Component, OnInit } from '@angular/core';
import { AuthService } from '../services/auth.service';
import { Router } from '@angular/router';

import { HttpClient } from '@angular/common/http';
@Component({
  selector: 'app-register',
  templateUrl: './register.component.html',
  styleUrls: ['./register.component.css']
})
export class RegisterComponent implements OnInit {

  constructor(
         private router: Router,
         private authService:AuthService,
        ) { }



  ngOnInit(): void {
  }

  registerData = {
    username: '',
    password:'',
    email:'',
    confirmpassword:'',
  }
  isPwdMatched: boolean = false;
  pwdnotmatched: string = "Passwords do not match!";
  registerUser = (registerForm: any) =>{
    this.authService!.register(registerForm)
    .subscribe(
      {
      next:(response) => {                          
        try{
        console.log(response);   
        this.router.navigateByUrl("/login");

        }
        catch (err){
          console.log(err);
         
        }
        
      },
      error:(error) => {                           
        console.log("erorr: ", error); 
      },
      complete: () => {                                   
        console.error('Request completed')     
         
      }
    }
      );
  }
  checkPwdMatched = () =>{
    
    if(this.registerData.password===this.registerData.confirmpassword) 
      this.isPwdMatched=true;
      else this.isPwdMatched=false;
  }

}

To use a service in a component, you have to inject the service into the constructor of the component.
In Angular, we use [(ngModel)] selector to bind (two-way binding) data defined in register.component.ts file to form controls in register.component.html file.

register/register.component.html
    <div class="reg-form">
            <div class="card-header">  
                <h3 class="mb-0">Register</h3>  
            </div>  
            <div class="card-body">  
                
                  <form class="form" #newUserForm="ngForm" (ngSubmit)="registerUser(newUserForm.value)">  
                    <div class="form-group row">  
                        <label for="" class="col-sm-1">Username</label>  
                        <div class="col-sm-5">
                        <input [(ngModel)]="registerData.username" name="username" type="text" class="form-control rounded-0" required>  
                        </div>    
                    </div> 
                    <div class="form-group row">  
                        <label for="" class="col-sm-1">Email</label>  
                        <div class="col-sm-5">
                        <input [(ngModel)]="registerData.email" name="email" type="text" class="form-control rounded-0" required>  
                        </div>    
                    </div>  
                    <div class="form-group row">  
                        <label for="" class="col-sm-1">Password</label> 
                        <div class="col-sm-5"> 
                        <input  (mouseout)="checkPwdMatched()" [(ngModel)]="registerData.password" name="password" type="password" class="form-control rounded-0" required>  
                        </div>    
                    </div> 
                    <div class="form-group row">  
                        <label for="" class="col-sm-1">Confirm Password</label> 
                        <div class="col-sm-5"> 
                        <input (mouseout)="checkPwdMatched()" [(ngModel)]="registerData.confirmpassword" name="confirmpassword" type="password" class="form-control rounded-0" required>  
                        </div>    
                    </div> 
                    <div class="form-group row">  
                        <div class="col-sm-10"  *ngIf="isPwdMatched"> 
                        <button type="submit" class="btn btn-primary float-right">Register</button>  
                        
                        </div>
                       
                        <div  role="alert"  *ngIf="!isPwdMatched">
                        <p class="alert-danger">{{pwdnotmatched}}</p> 
                        </div>
                    </div>

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

register/register.component.css
.reg-form{
    padding-left: 20%;
}

login/login.component.ts

import { Component, OnInit } from '@angular/core';
import { AuthService } from '../services/auth.service';
import { HttpClient } from '@angular/common/http';
import { ActivatedRoute, Router } from '@angular/router';
import jwt_decode from "jwt-decode";
@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {

  constructor(private route: ActivatedRoute,private router: Router,private authService:AuthService,private http: HttpClient) { }

  public loginData = {
    username: '',
    password:'',
  }
  logfailed='';

  ngOnInit(): void {
   
  }
  login = (logForm: any) =>{
    this.authService!.loggin(logForm)
    .subscribe(
      {
      next:(response) => {                          
        try{
       
        jwt_decode(response.token);
        localStorage.setItem('token',response.token);
        this.router.navigateByUrl("/products");
            }
        catch (err){
          console.log(err);
          this.logfailed = 'Invalid user!';
        }
        
      },
      error:(error) => {                     
        console.log("erorr: ", error); 
      },
      complete: () => {                                  
        console.error('Request completed')      
       
      }
    }
    );
  }

}

login/login.component.html
 <div class="login-form">
            <div class="card-header">  
                <h3 class="mb-0">Login</h3>  
            </div>  
            <div class="card-body">  
                
                  <form class="form" #newUserForm="ngForm" (ngSubmit)="login(newUserForm.value)">  
                    <div class="form-group row">  
                        <label for="" class="col-sm-1">Username</label>  
                        <div class="col-sm-5">
                        <input [(ngModel)]="loginData.username" name="username" type="text" class="form-control rounded-0" required>  
                        </div>    
                    </div>  
                    <div class="form-group row">  
                        <label for="" class="col-sm-1">Password</label> 
                        <div class="col-sm-5"> 
                        <input [(ngModel)]="loginData.password" name="password" type="password" class="form-control rounded-0" required>  
                        </div>    
                    </div> 
                    <div class="form-group row">  
                        <div class="col-sm-10"> 
                        <button type="submit" class="btn btn-primary float-right">Login</button>  
                        Don't have account?<a routerLink="/register" class="btn">Register</a> 
                        
                        <p class="alert-danger" role="alert">{{logfailed}}</p>
                     </div>
			        </div>
					
                </form>  
            </div>  
        </div>

login/login.component.css
.login-form{
    padding-left: 20%;
}
services/auth.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
import { HttpHeaders } from '@angular/common/http';
import jwt_decode from "jwt-decode";
import {api_url_root} from "../app.constants";

@Injectable({
  providedIn: 'root'
})
export class AuthService {

  constructor(private http:HttpClient) { }
  baseUrl:string=api_url_root+"api/";

  headers = new HttpHeaders()
  .set('Content-Type', 'application/json')

  public getCurrentUser(){
      
      let token=this.getToken();
      
      if(token!==null)
        return(jwt_decode(token || '{}'));
      else return null;  
    
  }
  public isLoggedin(){

    let ustr=this.getCurrentUser();
    let currentTimeInMilliseconds=Date.now();
    if(ustr!==null){
    let user=JSON.parse(JSON.stringify(ustr));
      if(user.data && user.data.user_id && user.data.user_id!=undefined){
           if(user.exp<=currentTimeInMilliseconds/1000) // check if token expired
          return false;
        else return true;  
      }
      else return false;
    }
    else 
    {
      return false;
    }
  }
  public getToken(){
    return localStorage.getItem('token');
  }

  public removeToken(): void{
    localStorage.removeItem('token');
  }
public loggin(logForm: any): Observable<any>{ const body=JSON.stringify(logForm); return this.http.post(this.baseUrl+"login",body,{'headers':this.headers}) .pipe( map((data) => { return data; }), catchError((err) => { console.error(err); throw err; } ) ) } public register(regForm: any): Observable<any>{ const body=JSON.stringify(regForm); return this.http.post(this.baseUrl+"register",body,{'headers':this.headers}) .pipe( map((data) => { return data; }), catchError((err) => { console.error(err); throw err; } ) ) } }

app/app.constants.ts
export const api_url_root='http://localhost/mysite/';


We decode a token using jwt-decode package. So, run the command below to install jwt-decode into the app.
ang14-client>npm install jwt-decode


In Angular, we use HttpClient service to perform request to APIs. HttpClient method calls return observables that can be subscribed using subscribe() method to get responses from the APIs. As you see in the auth.service.ts file above, the register and login methods return observables and the register and login components subscribe to received data from the observables.

Update app/app.component.ts file to check if a user is logged and to handle user logout.

import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { AuthService } from './services/auth.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
 
  public isExpanded = false;
  constructor(
    private router: Router,
    private _authservice: AuthService){  }
   
  public toggleMenu() {
    this.isExpanded = !this.isExpanded;
  }
 
  public isLoggedIn(){
    return this._authservice.isLoggedin();
  }

  public logout(){
    this._authservice.removeToken();
    this.router.navigateByUrl('/');
  }

}


Update app/app.routing-module.ts file to make register and login routes.

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { EditproductComponent } from './editproduct/editproduct.component';
import { LoginComponent } from './login/login.component';
import { ProductComponent } from './product/product.component';
import { RegisterComponent } from './register/register.component';

const routes: Routes = [

  { path: 'login', component: LoginComponent },
  { path: 'register', component: RegisterComponent },


];
@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

Here is the final app.module.ts file.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';

import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

import { MatSidenavModule } from "@angular/material/sidenav";
import { MatIconModule } from "@angular/material/icon";
import { MatListModule } from "@angular/material/list";
import { MatTooltipModule } from "@angular/material/tooltip";
import { MatButtonModule } from "@angular/material/button";
import {MatExpansionModule} from '@angular/material/expansion';
import {MatTreeModule} from '@angular/material/tree';

import { SideBarComponent } from './side-bar/side-bar.component';
import { RegisterComponent } from './register/register.component';
import { LoginComponent } from './login/login.component';

import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';


@NgModule({
  declarations: [
    AppComponent,
    SideBarComponent,
    LoginComponent,
    RegisterComponent,

  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    BrowserAnimationsModule,
    FormsModule,
    HttpClientModule,
    MatTreeModule,
    MatSidenavModule,
    MatListModule,
    MatIconModule,
    MatTooltipModule,
    MatButtonModule,
    MatExpansionModule,
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }


Save and run the project. Make sure Apache and MYSQL are running. Try create a new user and login.





Angular Tutorial: Product Listing & Paging

Comments

Popular posts from this blog

Angular with PHP & MYSQL to display products list & paging

Angular Upload Form Data & Files

PHP Mysql Database Migration Using Phinx