Angular2
AngularFire2
Angular CLI
A brave and "brand" new world
Who am I?
- I'm doing internet solar laps (years) since 1999
- Developing with JavaScript since 2006
- In Angular dreamland since 2013
- I DO NOT KNOW EVERYTHING!!!
- I Still have lots to do to improve, but I'm having fun a long time ago!
https://slides.com/josefduran/angular2-angularfire2-angular-cli/
Are we production ready?
- Angular2 is now release candidate
- Angular CLI is usable, but still missing more features
- AngularFire is still in beta, but a lot of improvements has been done already, develop with caution
- Documentation has improved but there are still some chapters pointing to previous versions
- Angular CLI still has some TS compilations errors due to FilesGlob config...
- Injection of dependencies in routes is not completely done by CLI
Let's dive in!
Install Angular CLI
Remember dependencies: NodeJS 4 and up
$ npm install -g angular-cli
github repo: https://github.com/angular/angular-cli
Create new project
$ ng new PROJECT_NAME
it will create the project folder and download initial dependencies needed
$ ng new simplechat
Project name: simplechat
Install AngularFire 2 & Firebase
$ npm install angularfire2 firebase@2.4.2 --save
There are a few steps for doing this...
This is based on the documentation on AngularFire2 repo and modified a little bit to fit our purposes.
Fixed to include proper version of Firebase
https://github.com/angular/angularfire2/
Install typings
$ npm install typings -g
$ typings install --save --ambient firebase
this is so typescript can work with the Firebase lib
Include AngularFire 2 and Firebase in the vendor files
/* global require, module */
var Angular2App = require('angular-cli/lib/broccoli/angular2-app');
module.exports = function(defaults) {
return new Angular2App(defaults, {
vendorNpmFiles: [
'systemjs/dist/system-polyfills.js',
'systemjs/dist/system.src.js',
'zone.js/dist/*.js',
'es6-shim/es6-shim.js',
'reflect-metadata/*.js',
'rxjs/**/*.js',
'@angular/**/*.js',
// above are the existing entries
// below are the AngularFire entries
'angularfire2/**/*.+(js|js.map)',
'firebase/lib/*.+(js|js.map)'
]
});
};
in: angular-cli-build.js
Build And check
$ ng build
Just to make sure we had everything ok
in: /dist/vendor folder we should have angularfire2 and firebase folders.
Let's modify System.js
/** Map relative paths to URLs. */
const map: any = {
'firebase': 'vendor/firebase/lib/firebase-web.js',
'angularfire2': 'vendor/angularfire2'
};
/** User packages configuration. */
const packages: any = {
angularfire2: {
defaultExtension: 'js',
main: 'angularfire2.js'
}
};
in: /src/system-config.ts
go to Firebase and create an account
Create an account and create a new database.
You will need to setup auth methods (we are going to use Github later) you can do it now or later. Remember to follow appropriate steps depending on the social login service you want to use.
Let's modify Angular Bootstrap
import { bootstrap } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { SimplechatAppComponent, environment } from './app/';
import { FIREBASE_PROVIDERS, defaultFirebase } from 'angularfire2';
if (environment.production) {
enableProdMode();
}
bootstrap(SimplechatAppComponent, [
FIREBASE_PROVIDERS,
defaultFirebase('https://<your-firebase-app>.firebaseio.com')
]);
/src/main.ts, inject the Firebase providers, and specify your default Firebase
remember to replace <your-firebase-app> in the default Firebase url
Let's create our first route
$ ng generate route login
it will generate the component and inject the route data in the inmediate parent component
Let's set login as the root route
@Routes([
{path: '/login', component: LoginComponent}
])
in: /src/app/spdyjs.component.ts
@Routes([
{path: '/', component: LoginComponent}
])
Change path for root
Now the old injection problem in routes is solved, but we don't see the login component showing below our title.
Fixing ng-cli code errors
There is a constructor instantiating the router missing from the code in our main component simplechat.component.ts
import { Component } from '@angular/core';
import { LoginComponent } from './+login';
import { Router, Routes, ROUTER_DIRECTIVES, ROUTER_PROVIDERS} from '@angular/router';
@Component({
moduleId: module.id,
selector: 'medjs-app',
templateUrl: 'medjs.component.html',
styleUrls: ['medjs.component.css'],
directives: [ROUTER_DIRECTIVES],
providers: [ROUTER_PROVIDERS]
})
@Routes([
{path: '/', component: LoginComponent}
])
export class MedjsAppComponent {
title = 'medjs works!';
// missing constructor here !!!
}
import { Component } from '@angular/core';
import { LoginComponent } from './+login';
import { Router, Routes, ROUTER_DIRECTIVES, ROUTER_PROVIDERS} from '@angular/router';
@Component({
moduleId: module.id,
selector: 'medjs-app',
templateUrl: 'medjs.component.html',
styleUrls: ['medjs.component.css'],
directives: [ROUTER_DIRECTIVES],
providers: [ROUTER_PROVIDERS]
})
@Routes([
{path: '/', component: LoginComponent}
])
export class MedjsAppComponent {
title = 'medjs works!';
constructor(private router: Router) { }
}
final result
We have our first route!!!
now some auth will be cool
- We'll use Github auth
- You'll need to setup the app in you Github account
- Also copy pass keys, secrets and whatever security sentences or phrases the oauth process requires to.
- This has been already setup!!!
Configure application in bootstrap
import { bootstrap } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { SimplechatAppComponent, environment } from './app/';
import {FIREBASE_PROVIDERS,
defaultFirebase,
AngularFire,
AuthMethods,
AuthProviders,
firebaseAuthConfig} from 'angularfire2';
if (environment.production) {
enableProdMode();
}
bootstrap(SimplechatAppComponent, [
ROUTER_PROVIDERS,
FIREBASE_PROVIDERS,
defaultFirebase('https://<your-firebase-app>.firebaseio.com'),
firebaseAuthConfig({
provider: AuthProviders.Github,
method: AuthMethods.Popup
})
]);
in: /src/main.ts
Let's edit our login.component.ts
import { AngularFire, AuthProviders, AuthMethods } from 'angularfire2';
Let's inject firebase auth on it
constructor(public af: AngularFire) {
this.af.auth.subscribe(auth => console.log(auth));
}
create a constructor to use it
<div *ngIf="af.auth">{{ (af.auth | async).auth.token.email }}</div>
<button (click)="login()">Login With Github</button>
and modify the HTML template adding:
What about an interceptor?
In Angular 1.x we did some "ui-router" magic with an interceptor to prevent entering paths without proper auth... How we can so this here?
we know the drill...
$ ng generate route chat
Let's create our second route
Let's get back to our simplechat.component.ts
import { AngularFire, FirebaseListObservable, AuthProviders, AuthMethods } from 'angularfire2';
Let's inject the needed dependencies for it
constructor(private router: Router, public af: AngularFire) {
this.af.auth.subscribe(auth => {
// interceptor
if (auth) {
if (auth.uid) {
this.router.navigate(['/chat']);
}
} else {
this.router.navigate(['/']);
}
});
}
building some Firebase Auth observables to handle the routes permissions
import { Component } from '@angular/core';
import { Router, Routes, ROUTER_DIRECTIVES} from '@angular/router';
import { AngularFire, FirebaseListObservable, AuthProviders, AuthMethods } from 'angularfire2';
import { ChatComponent } from './+chat';
import { LoginComponent } from './+login';
@Component({
moduleId: module.id,
selector: 'simplechat-app',
templateUrl: 'simplechat.component.html',
styleUrls: ['simplechat.component.css'],
directives: [ROUTER_DIRECTIVES]
})
@Routes([
{path: '/', component: LoginComponent},
{path: '/chat', component: ChatComponent}
])
export class SimplechatAppComponent {
title = 'simplechat works!';
constructor(private router: Router, public af: AngularFire) {
this.af.auth.subscribe(auth => {
// interceptor
if (auth) {
if (auth.uid) {
this.router.navigate(['/chat']);
}
} else {
this.router.navigate(['/']);
}
});
}
logout() {
this.af.auth.logout();
}
}
final result in simplechat.component.ts
Awesome! it's working
how about a logout?
in our main component (simplechat.component.ts): piece of cake!
logout() {
this.af.auth.logout();
}
and call the method in the template (simplechat.component.html)
<h1>
{{title}}
</h1>
<a href="javascript:;" (click)="logout()" *ngIf="af.auth">logout</a>
<router-outlet></router-outlet>
Let's
get to business
We now have our main project and some auth with it. We can dive now in the chat app!
import { Component, OnInit } from '@angular/core';
import {AngularFire, FirebaseListObservable} from 'angularfire2';
@Component({
moduleId: module.id,
selector: 'app-chat',
templateUrl: 'chat.component.html',
styleUrls: ['chat.component.css']
})
export class ChatComponent implements OnInit {
messages: FirebaseListObservable<any[]>;
email:string;
constructor(public af: AngularFire) {
this.messages = af.database.list('/messages');
this.af.auth.subscribe(auth => {
this.email = auth.github.email;
});
}
add(newMsg: string) {
this.messages.push({
email: this.email,
text: newMsg
});
}
ngOnInit() {
}
}
a little magic from AngularFire2
Let's edit chat.component.ts
<p>
chat works!
</p>
<form (ngSubmit)="add(newmsg.value)" #chatForm="ngForm">
<input type="text" #newmsg />
<button type="submit">send</button>
</form>
<ul *ngIf="messages">
<li *ngFor="let item of messages | async">
{{ item.email }}: {{ item.text }}
</li>
</ul>
now on the template
chat.component.html
Bonus track: Let's deploy
$ npm install -g firebase-tools
$ firebase login
$ firebase init
$ firebase deploy
We're going to use Firebase hosting for rapid deployment and testing, let's install it.
follow on console instructions on each step
References
https://github.com/josefduran/spdyjs
https://angular.io/docs/
https://github.com/angular/angularfire2
https://github.com/angular/angular-cli
https://firebase.google.com/docs/cli
Thank you!
Angular2, AngularFire2 & Angular CLI
By Jose Fernando Duran
Angular2, AngularFire2 & Angular CLI
- 2,335