Suresh Rohan's Blog

This blog is all about Java, J2EE,Spring, Angular, React JS, NoSQL, Microservices, DevOps, BigData, Tutorials, Tips, Best practice, Interview questions, Views, News, Articles, Techniques, Code Samples, Reference Application and much more

Thursday, January 25, 2018

Create a Project with Angular CLI

Image result for wallpaper

Create a Project with Angular CLI

It’s cool that you created an API to display a list of beers, but APIs aren’t that cool without a UI. In this section, you’ll create a new Angular app, build services to fetch beers/images, and create components to display this data.
To create an Angular project, make sure you have Node.js and the latest Angular CLI installed.
npm install -g @angular/cli@latest
Run ng --version to confirm you’re using version 1.0.0 (or later). From a terminal window, cd into the root of the spring-boot-angular-example directory and run the following command.
ng new client
This will create a new client directory and run npm install to install all the necessary dependencies. To verify everything works, run ng e2e in a terminal window. If everything works, you should see output like the following in your terminal.
[10:02:13] I/launcher - Running 1 instances of WebDriver
[10:02:13] I/direct - Using ChromeDriver directly...
Jasmine started

  client App
    ✓ should display welcome message

Executed 1 of 1 spec SUCCESS in 1 sec.
[10:02:16] I/launcher - 0 instance(s) of WebDriver still running
[10:02:16] I/launcher - chrome #01 passed
TIP: If you’re just getting started with Angular, you might want to watch this video of my recent Getting Started with Angular webinar.
If you’d rather not use the command line and have IntelliJ IDEA (or WebStorm) installed, you can create a new Static Web Project and select Angular CLI.
IntelliJ new Static Web project

Create a BeerListComponent and BeerService

Thus far, you’ve created a good-beers API and an Angular app, but you haven’t created the UI to display the list of beers from your API. To do this, create a <beer-list> component by running Angular CLI’s generate component command.
$ ng generate component beer-list
  create src/app/beer-list/beer-list.component.css (0 bytes)
  create src/app/beer-list/beer-list.component.html (28 bytes)
  create src/app/beer-list/beer-list.component.spec.ts (643 bytes)
  create src/app/beer-list/beer-list.component.ts (280 bytes)
  update src/app/app.module.ts (406 bytes)
TIP: There is a g alias for generate and a c alias for component, so you can type ng g c beer-list too.
Create a beer service:
$ ng g s beer
  create src/app/beer.service.spec.ts (362 bytes)
  create src/app/beer.service.ts (110 bytes)
Create a src/app/shared/beer directory and move beer.service.* into it.
mkdir -p src/app/shared/beer
mv src/app/beer.service.* src/app/shared/beer/.
Create a src/app/shared/index.ts file and export the BeerService. The reason for this file is so you can export multiple classes and import them in one line rather than multiple.
export * from './beer/beer.service';
Modify beer.service.ts to call the “good-beers” API service.
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';

@Injectable()
export class BeerService {

  constructor(private http: HttpClient) {}

  getAll(): Observable<any> {
    return this.http.get('http://localhost:8080/good-beers');
  }
}
Open src/app/app.module.ts and add HttpClientModule as an import.
import { HttpClientModule } from '@angular/common/http';

@NgModule({
  ...
  imports: [
    BrowserModule,
    HttpClientModule
  ],
  ...
})
Modify beer-list.component.ts to use the BeerService and store the results in a local variable. Notice that you need to add the service as a provider in the @Component definition or you will see an error.
import { Component, OnInit } from '@angular/core';
import { BeerService } from '../shared';

@Component({
  selector: 'app-beer-list',
  templateUrl: './beer-list.component.html',
  styleUrls: ['./beer-list.component.css'],
  providers: [BeerService]
})
export class BeerListComponent implements OnInit {
  beers: Array<any>;

  constructor(private beerService: BeerService) { }

  ngOnInit() {
    this.beerService.getAll().subscribe(
      data => {
        this.beers = data;
      },
      error => console.log(error)
    )
  }
}
Modify beer-list.component.html so it renders the list of beers.
<h2>Beer List</h2>

<div *ngFor="let b of beers">
  {{b.name}}
</div>
Update app.component.html to have the BeerListComponent rendered when you’re logged in.
<app-beer-list></app-beer-list>
Make sure both apps are started (with mvn spring-boot:run in the server directory, and ng serve in the client directory) and navigate to http://localhost:4200. You should see an error in your console that you means you have to configure cross-origin resource sharing (CORS) on the server.
Failed to load http://localhost:8080/good-beers: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4200' is therefore not allowed access.
To fix this issue, you’ll need to configure Spring Boot to allow cross-domain access from http://localhost:4200.

Configure CORS for Spring Boot

In the server project, open BeerController.java and add a @CrossOrigin annotation to enable cross-origin resource sharing (CORS) from the client (http://localhost:4200).
import org.springframework.web.bind.annotation.CrossOrigin;
...
    @GetMapping("/good-beers")
    @CrossOrigin(origins = "http://localhost:4200")
    public Collection<Beer> goodBeers() {
After making these changes, you should be able to see a list of beers from your Spring Boot API.
Beer List in Angular
To make it look a little better, add a Giphy service to fetch images based on the beer’s name. Create src/app/shared/giphy/giphy.service.ts and place the following code inside it.
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import 'rxjs/add/operator/map';

@Injectable()
// http://tutorials.pluralsight.com/front-end-javascript/getting-started-with-angular-2-by-building-a-giphy-search-application
export class GiphyService {

  // Public beta key: https://github.com/Giphy/GiphyAPI#public-beta-key
  giphyApi = '//api.giphy.com/v1/gifs/search?api_key=dc6zaTOxFJmzC&q=';

  constructor(public http: HttpClient) {
  }

  get(searchTerm) {
    const apiLink = this.giphyApi + searchTerm;
    return this.http.get(apiLink).map((response: any) => {
      if (response.data.length > 0) {
        return response.data[0].images.original.url;
      } else {
        return 'https://media.giphy.com/media/YaOxRsmrv9IeA/giphy.gif'; // dancing cat for 404
      }
    });
  }
}
Add an export for this class in src/app/shared/index.ts.
export * from './beer/beer.service';
export * from './giphy/giphy.service';
Then add it to BeerListComponent to set a giphyUrl on each beer object.
import { Component, OnInit } from '@angular/core';
import { BeerService, GiphyService } from '../shared';

@Component({
  selector: 'app-beer-list',
  templateUrl: './beer-list.component.html',
  styleUrls: ['./beer-list.component.css'],
  providers: [BeerService, GiphyService]
})
export class BeerListComponent implements OnInit {
  beers: Array<any>;

  constructor(private beerService: BeerService,
              private giphyService: GiphyService) { }

  ngOnInit() {
    this.beerService.getAll().subscribe(
      data => {
        this.beers = data;
        for (const beer of this.beers) {
          this.giphyService.get(beer.name).subscribe(url => beer.giphyUrl = url);
        }
      },
      error => console.log(error)
    )
  }
}
Then update beer-list.component.html to include a reference to this image.
<div *ngFor="let b of beers">
  {{b.name}}<br>
  <img width="200" src="{{b.giphyUrl}}" alt="{{b.name}}">
</div>
The result should look something like the following list of beer names with images.
Beer list with Giphy images
You’ve just created an Angular app that talks to a Spring Boot API using cross-domain requests. Congratulations!

No comments:

Post a Comment