In the previous post, We made a big step, our Angular Application can exchange data with a remote server. But up to now, we don’t have any mention on Angular navigations. So in the tutorial, JavaSampleApproach will show you how to navigate among the views with Angular Routing.
Angular 6 Update:
– Angular 6 Routing/Navigation – with Angular Router Service
– Angular 6 dynamic Navigation Bar – add/remove Route dynamically
Related articles:
– How to use Angular Http Client to fetch Data from SpringBoot RestAPI – Angular 4
– How to integrate Angular 4 with SpringBoot Web App and SpringToolSuite
– How to use Angular HttpClient to POST, PUT, DELETE data on SpringBoot Rest APIs – Angular 4
– Angular 4 + Spring JPA + PostgreSQL example | Angular 4 Http Client – Spring Boot RestApi Server
– Angular 4 + Spring JPA + MySQL example | Angular 4 Http Client – Spring Boot RestApi Server
Contents
- I. Technologies
- II. Angular Routing
- III. Practice
- 1. Create an App Routing Module
- 2. Add new function for DataService
- 3. Implement a new CustomerComponent
- 4. Re-Implement CustomerDetailComponent
- 5. Re-Implement AppComponent
- 6. Add new @GetMapping – GetCustomer by Id in SpringBoot RestApi
- 7. Integrate Angular App and SpringBoot Server
- 8. Run & Check Results
- IV. Sourcecode
I. Technologies
– Java 1.8
– Maven 3.3.9
– Spring Tool Suite – Version 3.8.1.RELEASE
– Spring Boot: RELEASE
– Angular 4
II. Angular Routing
The previous post, our App just works with only 1 url: base href="/"
. And in the tutorial, we need to change the base url to '/jsa'
and do a navigation among views with difference urls:
We have 2 urls will show in browser address bar:
– http://localhost:4200/jsa/customer
– http://localhost:4200/jsa/detail/{id}
How it work?
– When we enter in browser address bar: http://localhost:4200
or http://localhost:4200/jsa
, our app will always redirect to http://localhost:4200/jsa/customer
with customer-list view.
– Then when we click on each customer item link on customer-list view, or We enter a link http://localhost:4200/jsa/detail/{id}
in browser address bar, the browser will show a customer detail view with the url http://localhost:4200/jsa/detail/{id}
.
– Press on Back button, the browser’s url will be backed one step to http://localhost:4200/jsa/customer
.
How to do it?
-> We can do the navigations with Angular Routing!
const routes: Routes = [ { path: '', redirectTo: '/customer', pathMatch: 'full' }, { path: 'detail/:id', component: CustomerDetailsComponent }, { path: 'customer', component: CustomersComponent }, ]; |
III. Practice
In the tutorial, we will re-use all the sourcecode that we had done with the previous post. So you can check out it for more details:
– How to use Angular Http Client to fetch Data from SpringBoot RestAPI – Angular 4
Step to do:
With Angular Client:
– Create an App Routing Module
– Add new function for DataService
– Implement a new CustomerComponent
– Re-Implement CustomerDetailComponent
– Re-Implement AppComponent
With SpringBoot Service:
– Add a @GetMapping function – getCustomer by Id
Deployment:
– Integrate Angular App and SpringBoot Server
– Run & Check results.
1. Create an App Routing Module
Under folder /angular4client/src/app, create a new file app-routing.module.ts:
– The url /detail/:id
will be served by CustomerDetailsComponent
– The url /customer
will be served by CustomersComponent
import { CustomerDetailsComponent } from './customer-details/customer-details.component'; import { CustomersComponent } from './customers/customers.component'; import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; const routes: Routes = [ { path: '', redirectTo: '/customer', pathMatch: 'full' }, { path: 'detail/:id', component: CustomerDetailsComponent }, { path: 'customer', component: CustomersComponent }, ]; @NgModule({ imports: [ RouterModule.forRoot(routes) ], exports: [ RouterModule ] }) export class AppRoutingModule {} |
What is Routes?
Routes is an array of route configurations. We see some common properties of Routers:
– path: uses the route matcher DSL.
– pathMatch: specifies the matching strategy.
– component: is a component type.
– redirectTo: is the replaced url fragment.
Need register AppRoutingModule with AppModule:
import { AppRoutingModule } from './app-routing.module'; ... @NgModule({ declarations: [ AppComponent, CustomerDetailsComponent, CustomersComponent ], imports: [ ... AppRoutingModule ] ... export class AppModule { } |
2. Add new function for DataService
– Create a function getCustomer by id:
... getCustomer(id: number): Promise<Customer> { const url = `${this.customersUrl}/${id}`; return this.http.get(url) .toPromise() .then(response => response.json() as Customer) .catch(this.handleError); } ... |
For sharing a singleton DataService with all Components in Angular App, register DataService in AppModule:
... import { DataService } from './data.service'; @NgModule({ ... providers: [DataService], ... }) export class AppModule { } |
Full sourcecode:
import { Injectable } from '@angular/core'; import { Http } from '@angular/http'; import { ActivatedRoute, Params } from '@angular/router'; import { Location } from '@angular/common'; import 'rxjs/add/operator/toPromise'; import { Customer } from './customer'; @Injectable() export class DataService { private customersUrl = 'api/customer'; // URL to web API constructor(private http: Http) { } // Get all customers getCustomers(): Promise<Customer[]> { return this.http.get(this.customersUrl) .toPromise() .then(response => response.json() as Customer[]) .catch(this.handleError); } getCustomer(id: number): Promise<Customer> { const url = `${this.customersUrl}/${id}`; return this.http.get(url) .toPromise() .then(response => response.json() as Customer) .catch(this.handleError); } private handleError(error: any): Promise<any> { console.error('Error', error); // for demo purposes only return Promise.reject(error.message || error); } } |
3. Implement a new CustomerComponent
Create a new CustomerComponent, see the new project’s structure:
we re-use the current implementation of AppComponent for CustomerComponent:
import { Component, OnInit } from '@angular/core'; import { Customer } from '../customer'; import { DataService } from '../data.service'; @Component({ selector: 'app-root', templateUrl: './customers.component.html', styleUrls: ['./customers.component.css'], }) export class CustomersComponent implements OnInit { customers: Customer[]; constructor(private dataService: DataService) {} getCustomers() { return this.dataService.getCustomers().then(customers => this.customers = customers); } ngOnInit(): void { this.getCustomers(); } } |
Implement CustomerComponent‘s view:
<h3 style="color:green">Customer List:</h3> <a *ngFor="let cust of customers" [routerLink]="['/detail', cust.id]" class="col-1-4"> <div> <h4>{{cust.id}} - {{cust.firstname}}</h4> </div> </a> |
[routerLink]
is used to add an anchor tag to the template that will create triggers
when having any clicks for navigating to the component: CustomerDetailComponent.
4. Re-Implement CustomerDetailComponent
Inject DataService, ActivatedRoute, Location to CustomerDetailsComponent:
export class CustomerDetailsComponent implements OnInit { ... constructor( private dataService: DataService, private route: ActivatedRoute, private location: Location ) {} ... |
Location is a service to interact with a browser’s URL. Depending on LocationStrategy, Location will either persist to the URL’s path or the URL’s hash segment.
ActivatedRoute: contains the information about a route that can be used to traverse and retrieve the state of router tree.
Full Sourcecode:
import { Component, OnInit, Input } from '@angular/core'; import { Customer } from '../customer'; import { DataService } from '../data.service'; import { ActivatedRoute, Params } from '@angular/router'; import { Location } from '@angular/common'; import 'rxjs/add/operator/switchMap'; @Component({ selector: 'app-customer-detail', templateUrl: './customer-details.component.html', styleUrls: ['./customer-details.component.css'], }) export class CustomerDetailsComponent implements OnInit { customer: Customer; constructor( private dataService: DataService, private route: ActivatedRoute, private location: Location ) {} ngOnInit(): void { this.route.params .switchMap((params: Params) => this.dataService.getCustomer(+params['id'])) .subscribe(customer => this.customer = customer); } goBack(): void { this.location.back(); } } |
We implement ngOnInit()
to get info of a customer by function: dataService.getCustomer(+params['id']))
.
‘+’ in +params['id']
is used to convert String type to number type.
Using Location, a goBack()
function navigates backward one step in the browser’s history stack.
About the view of CustomerDetailsComponent (customer-details.component.html), we add a goBack button:
<div *ngIf="customer"> <h4>{{customer.firstname}} details!</h4> <div> <label>id: </label>{{customer.id}} </div> <div> <label>First Name: </label>{{customer.firstname}} </div> <div> <label>Last Name: </label>{{customer.lastname}} </div> <div> <label>Age: </label>{{customer.age}} </div> </div> <button (click)="goBack()">Back</button> |
5. Re-Implement AppComponent
Now, change the implementation of AppComponent as below:
import { Component, OnInit } from '@angular/core'; import { Customer } from './customer'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'], }) export class AppComponent { } |
The AppComponent‘s view:
<h2 style="color:blue">JSA - Angular Routing!</h2> <router-outlet></router-outlet> |
router-outlet
is used by the router to indicate a place where to display routing components.
-> So the CustomerComponent and CustomerDetailComponent will be showed under AppComponent‘s view.
6. Add new @GetMapping – GetCustomer by Id in SpringBoot RestApi
In WebController.java, add new function: @GetMapping getCustomer
... @GetMapping(value="/customer/{id}", produces=MediaType.APPLICATION_JSON_VALUE) public Customer getCustomer(@PathVariable int id){ return this.customers.get(id); } ... |
7. Integrate Angular App and SpringBoot Server
Angular4Client and SpringBoot server work independently on ports 8080 and 4200.
Goal of below integration: the client at 4200 will proxy any /api requests to the server.
Step to do:
{ "/api": { "target": "http://localhost:8080", "secure": false } } |
– Edit package.json file for “start” script:
... "scripts": { "ng": "ng", "start": "ng serve --proxy-config proxy.conf.json", "build": "ng build", "test": "ng test", "lint": "ng lint", "e2e": "ng e2e" }, ... |
>>> More details at: How to integrate Angular 4 with SpringBoot Web App and SpringToolSuite
8. Run & Check Results
Build and Run the SpringBoot project with commandlines: mvn clean install
and mvn spring-boot:run
Run the Angular App with command: npm start
Make a request: http://localhost:4200/
, results:
–> Response’s data
–> Customer List
Click to Mary’s link, results:
-> Response’s data
–> Customer Details
Press Back button, the browser’s url will be backed one step to http://localhost:4200/jsa/customer
.
IV. Sourcecode
AngularRoutingClient
SpringBootAngularHttpGet
Last updated on October 10, 2018.
how to deploy? jar include angular project?
To Deploy SpringBoot server with Angular4 client
Firstly, You build angularclient with command
ng build -prod
We have 2 approaches to deployment SpringBoot server with angular4 client:
–> Manually copy all files from dist folder to /src/main/resources/static folder of SpringBoot server project.
–> Using Maven plugin maven-resources-plugin to copy all files from dist folder to /src/main/resources/static folder of SpringBoot server project.
Dears,
I deployed angular build to static folder of spring boot ran the spring boot application
first page works fine, but remaining routing is not working
thanks in advance
The url works fine when I click by mouse for each link. But when I try to hit in address bar the same address, the request goes to server and server show 404 error. How can I solve this?
Hi Habibur Rahman,
I had tried to reproduce your issue with our sourcecodes.
But the sources work well.
So You can download the sourcecodes and try more with it!
For more info about how to practice, you can refer at related video:
https://youtu.be/XgWRKT2SRac
Regards,
I am using import { HttpClient } from ‘@angular/common/http’; in data.service.ts since the Http is now depreciated. Do you know how to write getCustomers with this new HttpClient ? I am unable to parse the json using resp.json().
Below is the modified code but it still doesn’t work for me.
Hi dheer,
With new
HttpClient
, the service could be written as:On Component that calls service:
HTML page with
async
pipeline:Regards,
JSA.
Hello,
I’m having the same problem as @HabiburRahman. Navigating to other pages (using the links) from http://localhost:8080/jsa/customer works, however, after accessing same pages (from browser address bar) or reload the page I get Whitelabel Error Page 404.
I think that the request gets handled by spring first and not angular hence the 404.
Do you know can I get around this?
I’ve found a solution: you need a spring controller that forwards all the requests to your SPA (you still need to provide all the paths though).
https://stackoverflow.com/a/38778129/5247883