Quantcast
Viewing latest article 2
Browse Latest Browse All 15

Authenticating Firebase and Angular with Auth0: Part 2

This article was originally published on the Auth0.com blog, and is republished here with permission.

In this two-part tutorial series, we’ll learn how to build an application that secures a Node back end and an Angular front end with Auth0 authentication. Our server and app will also authenticate a Firebase Cloud Firestore database with custom tokens so that users can leave realtime comments in a secure manner after logging in with Auth0. The Angular application code can be found at the angular-firebase GitHub repo and the Node API can be found in the firebase-auth0-nodeserver repo.

The first part of our tutorial, Authenticating Firebase and Angular with Auth0: Part 1, covered:

  • intro and setup for Auth0 and Firebase
  • implementing a secure Node API that mints custom Firebase tokens and provides data for our app
  • Angular application architecture with modules and lazy loading
  • Angular authentication with Auth0 with service and route guard
  • shared Angular components and API service.

Authenticating Firebase and Angular with Auth0: Part 2

Part 2 of our tutorial will cover:

  1. Displaying Dogs: Async and NgIfElse
  2. Dog Details with Route Parameters
  3. Comment Model Class
  4. Firebase Cloud Firestore and Rules
  5. Comments Component
  6. Comment Form Component
  7. Realtime Comments
  8. Conclusion

Our completed app will look something like this:

Image may be NSFW.
Clik here to view.
Angular Firebase app with Auth0 custom tokens

Let’s pick up right where we left off at the end of Authenticating Firebase and Angular with Auth0: Part 1.

Displaying Dogs: Async and NgIfElse

Let’s implement the home page of our app — the dogs listing. We created the scaffolding for this component when we set up our Angular app’s architecture.

Important Note: Make sure your Node.js API is running. If you need a refresher on the API, refer to How to Authenticate Firebase and Angular with Auth0: Part 1 - Node API.

Dogs Component Class

Open the dogs.component.ts class file now and implement this code:

// src/app/dogs/dogs/dogs.component.ts
import { Component, OnInit } from '@angular/core';
import { Title } from '@angular/platform-browser';
import { ApiService } from '../../core/api.service';
import { Dog } from './../../core/dog';
import { Observable } from 'rxjs/Observable';
import { tap, catchError } from 'rxjs/operators';

@Component({
  selector: 'app-dogs',
  templateUrl: './dogs.component.html'
})
export class DogsComponent implements OnInit {
  pageTitle = 'Popular Dogs';
  dogsList$: Observable<Dog[]>;
  loading = true;
  error: boolean;

  constructor(
    private title: Title,
    private api: ApiService
  ) {
    this.dogsList$ = api.getDogs$().pipe(
      tap(val => this._onNext(val)),
      catchError((err, caught) => this._onError(err, caught))
    );
  }

  ngOnInit() {
    this.title.setTitle(this.pageTitle);
  }

  private _onNext(val: Dog[]) {
    this.loading = false;
  }

  private _onError(err, caught): Observable<any> {
    this.loading = false;
    this.error = true;
    return Observable.throw('An error occurred fetching dogs data.');
  }

}

After our imports, we’ll set up some local properties:

  • pageTitle: to set our page’s <h1> and <title>
  • dogsList$: the observable returned by our API HTTP request to fetch the dogs listing data
  • loading: to show a loading icon while the API request is being made
  • error: to display an error if something goes wrong fetching data from the API.

We’re going to be using the declarative async pipe to respond to the dogsList$ observable returned by our API GET request. With the async pipe, we don’t need to subscribe or unsubscribe in our DogsComponent class: the subscription process will be managed automatically! We just need to set up our observable.

We’ll make Title and ApiService available to our class by passing them to the constructor, and then set up our dogsList$ observable. We’ll use RxJS operators tap (previously known as the do operator) and catchError to call handler functions. The tap operator executes side effects but does not affect the emitted data, so it’s ideal for setting other properties. The _onNext() function will set loading to false (since data has been successfully emitted). The _onError() function will set loading and error appropriately and throw an error. As mentioned before, we don’t need to subscribe or unsubscribe from the dogsList$ observable because the async pipe (which we’ll add in the template) will handle that for us.

On initialization of our component, we’ll use ngOnInit() to spy on the OnInit lifecycle hook to set the document <title>.

That’s it for our Dogs component class!

Dogs Component Template

Let’s move on to the template at dogs.component.html:

<!-- src/app/dogs/dogs/dogs.component.html -->
<h1 class="text-center">{{ pageTitle }}</h1>

<ng-template #noDogs>
  <app-loading *ngIf="loading"></app-loading>
  <app-error *ngIf="error"></app-error>
</ng-template>

<div *ngIf="dogsList$ | async as dogsList; else noDogs">
  <p class="lead">
    These were the top <a href="http://www.akc.org/content/news/articles/the-labrador-retriever-wins-top-breed-for-the-26th-year-in-a-row/">10 most popular dog breeds in the United States in 2016</a>, ranked by the American Kennel Club (AKC).
  </p>
  <div class="row mb-3">
    <div *ngFor="let dog of dogsList" class="col-xs-12 col-sm-6 col-md-4">
      <div class="card my-2">
        <img class="card-img-top" [src]="dog.image" [alt]="dog.breed">
        <div class="card-body">
          <h5 class="card-title">#{{ dog.rank }}: {{ dog.breed }}</h5>
          <p class="text-right mb-0">
            <a class="btn btn-primary" [routerLink]="['/dog', dog.rank]">Learn more</a>
          </p>
        </div>
      </div>
    </div>
  </div>
</div>

<app-comments></app-comments>

There are a couple things in this template that we’ll take a closer look at:

...
<ng-template #noDogs>
  <app-loading *ngIf="loading"></app-loading>
  <app-error *ngIf="error"></app-error>
</ng-template>

<div *ngIf="dogsList$ | async as dogsList; else noDogs">
  ...
    <div *ngFor="let dog of dogsList" ...>
      ...

This code does some very useful things declaratively. Let’s explore.

First we have an <ng-template> element with a template reference variable (#noDogs). The <ng-template> element is never rendered directly. It’s intended to be used with structural directives (such as NgIf). In this case, we’ve created an embedded view with <ng-template #noDogs> which contains both the loading and error components. Each of these components will render based on a condition. The noDogs embedded view itself will not render unless instructed to.

So how (and when) do we tell this view to render?

The next <div *ngIf="... is actually an NgIfElse using the asterisk prefix as syntactic sugar. We’re also using the async pipe with our dogsList$ observable and setting a variable so we can reference the stream’s emitted values in our template (as dogsList). If something goes wrong with the dogsList$ observable, we have an else noDogs statement that tells the template to render the <ng-template #noDogs> view. This would be true before the data has been successfully fetched from the API, or if an error was thrown by the observable.

If dogsList$ | async has successfully emitted a value, the div will render and we can iterate over our dogsList value (which is expected to be an array of Dogs, as specified in our component class) using the NgForOf (*ngFor) structural directive to display each dog’s information.

As you can see in the remaining HTML, each dog will be displayed with a picture, rank, breed, and a link to their individual detail page, which we’ll create next.

View the Dogs component in the browser by navigating to your app’s homepage at http://localhost:4200. The Angular app should make a request to the API to fetch the list of dogs and display them!

Note: We’ve also included the <app-comments> component. Since we’ve generated this component but haven’t implemented its functionality yet, it should show up in the UI as text that says “Comments works!”

To test error handling, you can stop the API server (Ctrl+c in the server’s command prompt or terminal). Then try reloading the page. The error component should display since the API cannot be reached, and we should see the appropriate errors in the browser console:

Image may be NSFW.
Clik here to view.
Angular app with Node.js API showing data error

The post Authenticating Firebase and Angular with Auth0: Part 2 appeared first on SitePoint.


Viewing latest article 2
Browse Latest Browse All 15

Trending Articles