Two posts ago I wrote about Angular2 application and I showed how to add new component and service. This time I want to show you how to implement a service in Angular2 and call webApi from it.
I decided to create login service in angular app which calls SignIn method from webApi (request via http post method).
Ok, let’s start. I have login.component and login.service in my angular app. First we need to make sure if login service is imported in login.module.ts and if it is added to providers list.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import {LoginService} from './login.service'; @NgModule({ imports: [ CommonModule ], declarations: [], providers: [ LoginService ] }) export class LoginModule { } |
Next let’s implement the service.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
import { Injectable } from '@angular/core'; import { Http, Headers, Response, Request, RequestOptions, RequestMethod } from '@angular/http'; import { Observable } from 'rxjs'; import 'rxjs/add/operator/map'; import { Constants } from 'app/constants'; @Injectable() export class LoginService { private _signInAction ='login/signin'; constructor(private http: Http) { } signIn(username: string, password: string): Observable<boolean> { let userCredentials = { 'Username': username, 'Password': password }; let body = JSON.stringify(userCredentials); let headers = new Headers({ 'Content-Type': 'application/json','Accept': 'application/json' }); let options = new RequestOptions({ headers: headers }); console.log(Constants._apiUrl.concat(this._signInAction)); return this.http.post(Constants._apiUrl.concat(this._signInAction), body, options) .map((response: Response) => { console.log(response.json()); return true; }); } } |
First we need to import few things. You can ignore app/constants as you can see in my code, it’s just simple typescript class that contains constants. In the constructor we need to create http variable which will be used later.
SignIn function takes two parameters: username and password and returns boolean value. Then we have to construct http request that will be send to webApi. It’s very important to add headers that informs request contains json content, because webApi only accepts jsons. After http.post method there’s another method – map, which transforms the result to whatever we want.
Next is time to implement some code in login.component class. Let’s start from imports, don’t forget to import our service.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
import { Component, OnInit, Input } from '@angular/core'; import { Router } from '@angular/router'; import { LoginService } from './login.service'; import { Constants } from 'app/constants'; @Component({ selector: 'app-login', templateUrl: './login.component.html', styleUrls: ['./login.component.scss'], providers: [ LoginService ] }) export class LoginComponent implements OnInit { @Input() loggedUsername: string; private _username: string; private _password: string; private _hideSummaryError: boolean; private _hideUsernameError: boolean; private _hidePasswordError: boolean; constructor(private router: Router, private loginService: LoginService) { this._hidePasswordError = true; this._hideSummaryError = true; this._hideUsernameError = true; } ngOnInit() { } onKeyUp(event: KeyboardEvent) { let target = <HTMLFormElement>event.target; if (target.name === 'UserName') { this._username === '' ? this._hideUsernameError = false : this._hideUsernameError = true; } else if (target.name === 'Password') { this._password === '' ? this._hidePasswordError = false : this._hidePasswordError = true; } } onLogin() { if ((this._username === '' || this._username === undefined) && (this._password === '' || this._password === undefined)) { this._hideUsernameError = false; this._hidePasswordError = false; } else if (this._username === '' || this._username === undefined) { this._hideUsernameError = false; } else if (this._password === '' || this._password === undefined) { this._hidePasswordError = false; } else { this.loginService.signIn(this._username, this._password) .subscribe(result => { if (result === true) { localStorage.setItem(Constants.Username, this._username); this.loggedUsername = this._username; this.router.navigate(['/welcome']); } else { this._hideSummaryError = false; } }) } } } |
I have few variables in my login component, like username, password and 3 others that indicate an error. You can skip it, it’s not needed to achieve our goal from this post. I use it only to check if username and password are valid and show an error message in case they are not valid.
Let’s focus on onLogin() method. After few validations signIn method from login service is called with username and password which are passed as arguments. Subscribe method allows to define operation that we want to execute when result will come. I want to save username in localstorage and navigate to different component – welcome component.
What about login.component.html? It depends from you how you want to design it. There are a lot of samples in bootstrap 😉 Here is mine.
Basically you need to create a form.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
<form class="form-horizontal" method="post" (ngSubmit)="onLogin($event)" novalidate #loginForm="ngForm"> <div class="form-group"> <label for="username" class="cols-sm-2 control-label">Username</label> <div class="cols-sm-10"> <div class="input-group"> <span class="input-group-addon"><i class="fa fa-users fa" aria-hidden="true"></i></span> <input type="text" class="form-control" name="username" id="username" placeholder="Enter your Username" required [(ngModel)]="_username" (keyup)="onKeyUp($event)"/> </div> <span [hidden]="_hideUsernameError" class="field-validation-error">Username is required.</span> </div> </div> <div class="form-group"> <label for="password" class="cols-sm-2 control-label">Password</label> <div class="cols-sm-10"> <div class="input-group"> <span class="input-group-addon"><i class="fa fa-lock fa-lg" aria-hidden="true"></i></span> <input type="password" class="form-control" name="password" id="password" placeholder="Enter your Password" required [(ngModel)]="_password" (keyup)="onKeyUp($event)" /> </div> <span [hidden]="_hidePasswordError" class="field-validation-error">Password is required.</span> </div> </div> <div class="form-group "> <button type="submit" class="btn btn-primary btn-lg btn-block login-button">Login</button> </div> <div> <span [hidden]="_hideSummaryError" class="field-validation-error">Login failed.</span> </div> <div class="login-register"> <a href="index.php">Return</a> </div> </form> |
and add ngSubmit directive that enables binding expressions to onsubmit events. We have onLogin method in login component that will handle it. We need also to bind input controls to our model
1 |
[(ngModel)]="_username" |
It will bind value from this control to _username variable in component class. I have also method binds to keyup event, but it’s only for validating input data. onKeyUp method in the component is responsible for it.
It looks we have all. Our service in Angular2 is ready. Now it’s time to start app and try to call webApi, but we will take a look at it in the next post.