How to work with Angular Routing – Spring Boot + Angular

How to work with Angular Routing – Spring Boot + Angular

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
How to integrate Angular with SpringBoot Web App and SpringToolSuite
How to use Angular HttpClient to POST, PUT, DELETE data on SpringBoot Rest APIs – Angular
Angular + Spring JPA + PostgreSQL example | Angular Http Client – Spring Boot RestApi Server
Angular + Spring JPA + MySQL example | Angular 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

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

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 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 | May 27, 2017.

Last updated on March 26, 2021.



Related Posts


9 thoughts on “How to work with Angular Routing – Spring Boot + Angular”

    1. 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.

      1. 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

  1. 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?

  2. 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.

    Reply
  3. Hi dheer,

    With new HttpClient, the service could be written as:

    customers: Observable;
    // ...
    this.customers = this.customerService.getCustomersList();
    

    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?

  • Got Something To Say:

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

    *