HelloBeer goes Angular – Finale

Alright guys. This is the last and final episode of our – soon to be released on Netflix – blockbuster series of HelloBeerTM goes Angular starring lots of frustrated beer drinking developers. In this grande finale we’re gonna finish the app we developed in our previous blog posts here and here and add some much needed error handling, css styling and i18n.
The final code can be found here on Github.

Bootstrap CSS

I was using a bootstrap.css file that I snatched somewhere from the internet when I started developing the app, but I recently found out you can just add it as a dependency module. To install the bootstrap version I’ve been using you can add it to the project like this:

npm install bootstrap@3.3.2 --save

Now you can add the import to the styles.css file like this

@import '../node_modules/bootstrap/dist/css/bootstrap.css';

Error handling

The POST method of our REST service expects a beer name to be present in the JSON request. When you leave it blank the beer won’t be added to the inventory, the server will return an error and the JSON error message will be logged to the console. Let’s change that a bit and make it a more in-your-face-experience for the user.

First change the edit-beer.component.ts file to store a possible error in a model variable:

import {Component, EventEmitter, OnInit, Output} from '@angular/core';

import {ApiClientService} from "../services/beer";
import {Beer, Type} from '../services/beer/models';

@Component({
  selector: 'app-edit-beer',
  templateUrl: './edit-beer.component.html',
  styleUrls: ['./edit-beer.component.css']
})
export class EditBeerComponent implements OnInit {

  @Output() onBeerPosted = new EventEmitter<Beer>();

  public beer: Beer = {} as Beer;
  public beerTypes: string[];

  public error: string;

  constructor(private apiClientService: ApiClientService) {
    this.beerTypes = (Object.keys(Type));
  }

  /**
   * Call REST service to POST a beer
   */
  public postBeer(): void {
    this.apiClientService.addToBeerRepositoryUsingPOST(this.beer)
      .subscribe(resp => {
        this.pushBeer(resp.body)
      }, (error => {
        console.log(error);
        this.onError(error.error.message)
      }));
  }

  private pushBeer(beer: Beer): void {
    // add beer to app
    this.onBeerPosted.emit(beer);
    this.reset();
  }

  private onError(message: string): void {
    this.error = message;
  }

  private reset(): void {
    this.beer = {} as Beer;
    this.error = null;
  }

  ngOnInit() {
  }

}

And add the following html snippet at the top of our edit-beer.component.html page (just below the title).

<div [hidden]="!error" class="panel panel-danger panel-body">
  <span class="text-danger">{{error}}</span>
</div>

This will only show the div when there’s actually an error message there.
Now when we try to post a nameless beer to our inventory, we’ll see the error appearing on our screen, like this:
Screenshot-2018-3-5 HbAngularClient
It’s not the most helpful error message, but I’ll leave it up to the reader to pluck a better error message out of the quite verbose REST response.

i18n

Finally, let’s get rid of those ugly beer types. Again this took me a while to get it right, but in the end I found the module that got the job done. It’s called ngx-translate and I basically followed the steps explained on this how-to here.

First add the modules to the app:

npm install @ngx-translate/core --save
npm install @ngx-translate/http-loader --save

Alter the app.module.ts file (consult the how-to page):

import {NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {FormsModule} from "@angular/forms";
import {HttpClient, HttpClientModule} from '@angular/common/http';
// import ngx-translate and the http loader
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
import {TranslateHttpLoader} from '@ngx-translate/http-loader';

import {AppComponent} from './app.component';
import {EditBeerComponent} from './edit-beer/edit-beer.component';

import {ApiClientService} from './services/beer/index';

@NgModule({
  declarations: [
    AppComponent,
    EditBeerComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpClientModule,
    TranslateModule.forRoot({
      loader: {
        provide: TranslateLoader,
        useFactory: HttpLoaderFactory,
        deps: [HttpClient]
      }
    })
  ],
  providers: [ApiClientService],
  bootstrap: [AppComponent]
})
export class AppModule {
}

// required for AOT compilation
export function HttpLoaderFactory(http: HttpClient) {
  return new TranslateHttpLoader(http);
}

Next, inject the TranslateService in the app component:

....
import {TranslateService} from "@ngx-translate/core";
....
  constructor(private apiClientService: ApiClientService, private translateService: TranslateService) {
    translateService.setDefaultLang('en');
  }
....

Add the en.json file with the beer type translations to the assets/i18n directory:

{
  "LAGER": "Lager",
  "PILSNER": "Pilsner",
  "PALE_ALE": "Pale Ale",
  "INDIA_PALE_ALE": "India Pale Ale",
  "STOUT": "Stout",
  "OTHER": "Other"
}

Now you can add the translate pipes to the fields displaying the beer types (there’s one on the app.component.html and one on the edit-beer.component.html), like this:

{{beer.type | translate}}

Now test the application. If you’ve made no mistake it should look like this now (check the beer types, they’re nicely translated):
Screenshot-2018-3-5 HbAngularClient(1)

Summary

In these last three blog posts we’ve seen how relatively easy it is to build a small Angular app consuming a Swagger API. The typescript code for consumption was generated by the angular-swagger-client-generator module.

The combination of a Spring Boot back end and an Angular front end is quite popular. As a matter of fact there’s an open source generator out there built around these two frameworks, one that’s gaining quite a lot of traction lately.

In my next blog post I’m gonna market my HelloBeerTM beers to one of the largest groups of craft beer drinkers out there: the hipsters! You guessed it, time to check out JHipster!

References

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s