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