How to work with Angular Routing – Spring Boot + Angular 11
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 11
– How to integrate Angular 11 with SpringBoot Web App and SpringToolSuite
– How to use Angular HttpClient to POST, PUT, DELETE data on SpringBoot Rest APIs – Angular 11
– Angular 11 + Spring JPA + PostgreSQL example | Angular 11 Http Client – Spring Boot RestApi Server
– Angular 11 + Spring JPA + MySQL example | Angular 11 Http Client – Spring Boot RestApi Server
I. Technologies
– Java 1.8
– Maven 3.3.9
– Spring Tool Suite – Version 3.8.1.RELEASE
– Spring Boot: RELEASE
– Angular 11
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 11
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{ 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{ return this.http.get(this.customersUrl) .toPromise() .then(response => response.json() as Customer[]) .catch(this.handleError); } getCustomer(id: number): Promise { 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 { 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 11 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