How to work with Angular Routing – Spring Boot + Angular 11

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:

angular routing - list customers

angular routing - customer -details

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:

angular routing - new structure app

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

angular routing - customer -details - response data

–> Customer List

angular routing - list customers

Click to Mary’s link, results:

-> Response’s data

angular routing - customer -details - response Mary

–> Customer Details

angular routing - customer -details

Press Back button, the browser’s url will be backed one step to http://localhost:4200/jsa/customer.

IV. Sourcecode

AngularRoutingClient
SpringBootAngularHttpGet



By grokonez | March 26, 2021.


Related Posts


Got Something To Say:

Your email address will not be published. Required fields are marked *

*