So now we will take care of the authentication Blaze Templates, such as Join and Signup.
We already created a stub Angular 2 Components for them - we just need to implement them now.
This Todos project uses AccountTemplates package, which has a default style templates for signin and join pages - we do not want to use those and we want to implement it with Angular 2.
The style and template defined in imports/ui/accounts/accounts-templates.html and we will copy the thing we need and create a new Angular 2 template file that looks the same.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<div class="page auth"> <nav> <div class="nav-group"> <a href="#" class="js-menu nav-item"> <span class="icon-list-unordered"></span> </a> </div> </nav> <div class="content-scrollable"> <div class="wrapper-auth"> <div class="at-form"> <h1 class="title-auth">Join</h1> <p class="subtitle-auth">Signing in allows you to have private lists</p> <div class="at-pwd-form"> <form role="form" id="at-pwd-form"> </form> </div> </div> </div> </div></div>So this is the basic layout without the actual form fields, let's use it:
1
2
3
4
5
6
7
import {Component} from "@angular/core";@Component({ templateUrl: '/client/imports/components/join.html'})export class JoinComponent {}Now let's add the actual form:
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
</a> </div> </nav> <div class="content-scrollable"> <div class="wrapper-auth"> <div class="at-form"> <h1 class="title-auth">Join</h1> <p class="subtitle-auth">Signing in allows you to have private lists</p> <div class="list-errors"> <div *ngFor="let errorText of errors" class="list-item">{{errorText}}</div> </div> <div class="at-pwd-form"> <form id="at-pwd-form" (ngSubmit)="join()" #joinForm="ngForm"> <div class="input"> <input [(ngModel)]="model.email" required type="text" id="email" name="email" placeholder="Email" class="form-control" autocapitalize="none" autocorrect="off"> </div> <div class="input"> <input [(ngModel)]="model.password" required type="password" id="password" name="password" class="form-control" placeholder="Password" autocapitalize="none" autocorrect="off"> </div> <div class="input"> <input [(ngModel)]="model.passwordVerify" required type="password" id="password_verify" class="form-control" name="password_verify" placeholder="Password (Again)" autocapitalize="none" autocorrect="off"> </div> <button type="submit" class="btn-primary" [disabled]="!joinForm.form.valid">REGISTER
</button> </form> </div> </div> </div> </div></div>Let's understand what do we have here:
ngSubmit to the Component method join, and we give it a name joinForm using variable reference (more info here)ngControl which indicate that this input related to the form and effect it's validation.ngModel for the inputs.submit that disabled when the form is not valid.Great, now we need to add some code to the form:
errors array.join() method and create the actual user when join.So let's do it:
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
import {Component, NgZone} from "@angular/core";import {Router} from "@angular/router";class JoinModel { constructor(public email : string, public password : string, public passwordVerify : string) { }}@Component({ templateUrl: '/client/imports/components/join.html'})export class JoinComponent { private model : JoinModel; private errors : Array<string> = []; constructor(private router : Router, private zone: NgZone) { this.model = new JoinModel('', '', ''); } resetErrors() { this.errors = []; } join() { this.resetErrors(); if (this.model.password !== this.model.passwordVerify) { this.errors.push("Passwords does not match!"); return; } Accounts.createUser({ email: this.model.email, password: this.model.password}, (err) => {
if (err) { this.zone.run(() => { this.errors.push(err.reason); }); return; } this.router.navigate(['/']); }); }}And we also need to add an import for Angular 2 Forms Module, so let's do it:
7
8
9
10
11
12
13
28
29
30
31
32
33
34
35
import {Angular2BlazeTemplateModule} from "angular2-blaze-template";import {JoinComponent} from "./components/join.component";import {SigninComponent} from "./components/signin.component";import {FormsModule} from "@angular/forms";@NgModule({ // Components, Pipes, Directive...some lines skipped...imports: [
BrowserModule,
routing,
Angular2BlazeTemplateModule,
FormsModule
],
// Main Componentbootstrap: [MainComponent]
This Todo base project uses packages that intent to help developing Blaze Template with Meteor Accounts, and we no longer need it, and it is also "takes control" of sign-up, so we need to remove it.
So let's remove those packages, by running:
meteor remove useraccounts:unstyled useraccounts:flow-routing softwarerero:accounts-t9n
And we also perform some cleanup and remove some files that uses this packages - you can see those modifications in commit #7.6 (or here)
Great! now we need to make sure that there is an indication for the user that he's logged in, so let's go back to MainContainerComponent and and add currentUser field:
16
17
18
19
20
21
22
33
34
35
36
37
38
39
40
private menuOpen : boolean = false; private userMenuOpen : boolean = false; private lists: Observable<any>; private currentUser : Meteor.User; constructor(private router: Router) { this.isCordova = Meteor.isCordova;...some lines skipped...{userId: Meteor.userId()},
]
}).zone(); this.currentUser = Meteor.user(); }); }We put that code inside
autorunbecause we want it to update when the user login or logout.
Now we should be able to see the user's name if the main page - the only missing thing is to fix and add toggle for the user menu:
1
2
3
4
5
6
7
<div id="container" [ngClass]="{'menu-open': menuOpen, 'cordova': isCordova}"> <section id="menu"> <div *ngIf="currentUser" class="btns-group-vertical"> <a class="js-user-menu btn-secondary" (click)="userMenuOpen = !userMenuOpen"> <span *ngIf="userMenuOpen" class="icon-arrow-up"></span> <span *ngIf="!userMenuOpen" class="icon-arrow-down"></span>Now, let's do the same for the SigninComponent - it's very similar:
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
<div class="page auth"> <nav> <div class="nav-group"> <a href="#" class="js-menu nav-item"> <span class="icon-list-unordered"></span> </a> </div> </nav> <div class="content-scrollable"> <div class="wrapper-auth"> <div class="at-form"> <h1 class="title-auth">Signin</h1> <p class="subtitle-auth">Signing in allows you to have private lists</p> <div class="list-errors"> <div *ngFor="let errorText of errors" class="list-item">{{errorText}}</div> </div> <div class="at-pwd-form"> <form id="at-pwd-form" (ngSubmit)="join()" #joinForm="ngForm"> <div class="input"> <input [(ngModel)]="model.email" required type="text" id="email" name="email" placeholder="Email" class="form-control" autocapitalize="none" autocorrect="off"> </div> <div class="input"> <input [(ngModel)]="model.password" required type="password" id="password" name="password" class="form-control" placeholder="Password" autocapitalize="none" autocorrect="off"> </div> <button type="submit" class="btn-primary" [disabled]="!joinForm.form.valid">SIGN IN
</button> </form> </div> </div> </div> </div></div>And the Component:
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
import {Component, NgZone} from "@angular/core";import {Router} from "@angular/router";class SigninModel { constructor(public email : string, public password : string) { }}@Component({ templateUrl: '/client/imports/components/signin.html'})export class SigninComponent { private model : SigninModel; private errors : Array<string> = []; constructor(private router: Router, private ngZone: NgZone) { this.model = new SigninModel('', ''); } resetErrors() { this.errors = []; } join() { this.resetErrors(); Meteor.loginWithPassword(this.model.email, this.model.password, (err) => { if (err) { this.ngZone.run(() => { this.errors.push(err.reason); }); return; } this.router.navigate(['/']); }); }}That's it! we implemented the join/signin forms with Angular 2 !