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 Component
bootstrap: [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
autorun
because 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 !