Securing Angular 7 application with Spring Boot JWT Security

As we have secured our angular application using spring boot basic security. In this article , i will take you through all the steps to secure your angular application with spring boot JWT(JSON Web Token) security. Using Spring boot basic security , we can provide in token based authentication and authorization to our application.

We need to configure users and their roles in in separate configuration file. We are creating two projects here –

  1. Spring boot JWT security application – This will handle the authentication and authorization for our UI application.
  2. UI for Todo manager in angular – This is the Todo manager application which will leverage the spring boot security feature.

Part 1: Spring boot JWT security application

In this part , we will be creating a spring boot application which provides JWT security. Its basically a RESTful webservice which has endpoints to access and modify Todos information. To access the Todo information through API , user needs to authenticate himself. Below configuration enables basic security.

SecurityConfig.java

package com.myjavablog.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

	@Autowired
	private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;

	@Autowired
	private UserDetailsService jwtUserDetailsService;

	@Autowired
	private JwtRequestFilter jwtRequestFilter;

	@Autowired
	public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
		// configure AuthenticationManager so that it knows from where to load
		// user for matching credentials
		// Use BCryptPasswordEncoder
		auth.userDetailsService(jwtUserDetailsService).passwordEncoder(passwordEncoder());
	}

	@Bean
	public PasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
	}

	@Bean
	@Override
	public AuthenticationManager authenticationManagerBean() throws Exception {
		return super.authenticationManagerBean();
	}

	@Override
	protected void configure(HttpSecurity httpSecurity) throws Exception {
		// We don't need CSRF for this example
		httpSecurity.csrf().disable()
				// dont authenticate this particular request
				.authorizeRequests().antMatchers("/authenticate").permitAll().antMatchers(HttpMethod.OPTIONS, "/**")
				.permitAll().
				// all other requests need to be authenticated
				anyRequest().authenticated().and().
				// make sure we use stateless session; session won't be used to
				// store user's state.
				exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and().sessionManagement()
				.sessionCreationPolicy(SessionCreationPolicy.STATELESS);

		// Add a filter to validate the tokens with every request
		httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
	}
}

JwtAuthenticationController.java

Below is JwtAuthenticationController.java which has API endpoint to authenticate the user and provides us with JWT. createAuthenticationToken() method validates the user and generated the token for us which has expiration of 5*60*60 (5 Hours).

package com.myjavablog.controller;

import java.util.Objects;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.myjavablog.config.JwtTokenUtil;
import com.myjavablog.model.JwtRequest;
import com.myjavablog.model.JwtResponse;

@RestController
@CrossOrigin
public class JwtAuthenticationController {

	@Autowired
	private AuthenticationManager authenticationManager;

	@Autowired
	private JwtTokenUtil jwtTokenUtil;

	@Autowired
	private UserDetailsService jwtInMemoryUserDetailsService;

	@RequestMapping(value = "/authenticate", method = RequestMethod.POST)
	public ResponseEntity<?> createAuthenticationToken(@RequestBody JwtRequest authenticationRequest)
			throws Exception {

		authenticate(authenticationRequest.getUsername(), authenticationRequest.getPassword());

		final UserDetails userDetails = jwtInMemoryUserDetailsService
				.loadUserByUsername(authenticationRequest.getUsername());

		final String token = jwtTokenUtil.generateToken(userDetails);

		return ResponseEntity.ok(new JwtResponse(token));
	}

	private void authenticate(String username, String password) throws Exception {
		Objects.requireNonNull(username);
		Objects.requireNonNull(password);

		try {
			authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
		} catch (DisabledException e) {
			throw new Exception("USER_DISABLED", e);
		} catch (BadCredentialsException e) {
			throw new Exception("INVALID_CREDENTIALS", e);
		}
	}
}

TodoController.java

Below is the Rest controller class for managing Todo’s information –

package com.myjavablog.controller;

import com.myjavablog.model.Todo;
import com.myjavablog.model.User;
import com.myjavablog.repository.TodoRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;

@CrossOrigin(origins = "http://localhost:4200")
@RestController
@RequestMapping("/api")
public class TodoController {

    //@Autowired
    //private TodoRepository todoRepository;

    static List<Todo> list = new ArrayList<>();

    @GetMapping(produces = "application/json")
    @RequestMapping({ "/validateLogin" })
    public User validateLogin()
    {
        return new User("User successfully authenticated");
    }

    @GetMapping(produces = "application/json")
    @RequestMapping("/todos")
    public List<Todo> getTodos(){
        return list;
    }

    TodoController(){

        list.add(new Todo(1l,"Badminton", "Badminton at 6 am", "Pending"));
        list.add(new Todo(2l,"Cricket", "Cricket at 7 am", "Pending"));
        list.add(new Todo(3l,"Football", "Football at 8 am", "Pending"));
        list.add(new Todo(4l,"Cards", "Cards at 6 am", "Pending"));
        list.add(new Todo(5l,"TT", "TT at 6 am", "Completed"));
        list.add(new Todo(6l,"Golf", "Golf at 6 am", "Pending"));
        list.add(new Todo(7l,"Running", "Running at 6 am", "Pending"));
        list.add(new Todo(8l,"Walking", "Walking at 6 am", "Pending"));
        list.add(new Todo(9l,"Swimming", "Swimming at 6 am", "Completed"));
        list.add(new Todo(10l,"Reading", "Reading at 6 am", "Pending"));

        //return list;
    }

    @GetMapping("/todo/{id}")
    public Todo getTodo(@PathVariable Long id)
    {
        //return todoRepository.findById(id);

        for(Todo todo : list){

            if(todo.getId() == id){
                return todo;
            }
        }

        return null;
    }

    @DeleteMapping("/todo/{id}")
    public boolean deleteTodo(@PathVariable Long id){
        //todoRepository.deleteById(id);

        for(Todo todo : list){

            if(todo.getId() == id){
                list.remove(todo);
            }
        }

        return true;
    }

    @PostMapping("/todo")
    public Todo createTodo(@RequestBody Todo todo){

        list.add(todo);
        return todo;
        //return todoRepository.save(todo);
    }

    @PutMapping("/todo")
    public Todo updateTodo(@RequestBody Todo todo){


        for(Todo t : list){

            if(todo.getId() == t.getId()){
                list.remove(t);
                list.add(todo);
                return todo;
            }
        }

        return null;
        //return todoRepository.save(todo);
    }
}

JwtTokenUtil.java – This class is responsible for token generation.

JwtRequestFilter.java – All request to REST API are filtered through this class. Token is validated in each request for user authorization.

We can call the webservice through POSTMAN as below –

Get the Authentication Token
Call to todo API using Authentication token

Source code can be downloaded from below link –

Part 2: UI for Todo manager in angular 7

All the REST service calls are authenticated and authorized using the spring boot JWT security. Before calling todo services , we need to pass authorization header with all requests from UI.

In JWT token based security , we pass on base 64 encoded string of username and password to server as authorization header in below format –

Authorization Header = “Bearer ” + Base64Encoder(username:password)

Step 1: Create new angular application

Refer below post for creating new angular application –

Angular Installation and Setup

Step 2: Create modules for material and primeng components

Create two modules for material(material.module.ts) and primeng( primeng.module.ts ) to define all the related components required in application. These two modules are also required to be imported in main module (app.module.ts)

Please refer below link for primeng and material configuration –

CRUD Operations using primeng datatable and Material Design

Step 3: Create components (Presentation layer)

Create components named header, footer, login,logout and todo components for Todo Manager application.

Todo manager application shows all todos in primeng datatable . Also we are allowed to perform CRUD operations on all todos. All CRUD operations are done in todo component as below –

Todo component –

  • components\todo\todo.component.html
  • components\todo\todo.component.ts

Step 4: Add the routing for application (Application Navigation/Routing)

We have to create a route for the application navigation. Below file contains routing configuration –

  • src\app\app-routing.module.ts
import { NgModule, ViewChildren } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { TodoComponent } from './components/todo/todo.component';
import { TodoAddComponent } from './components/todo-add/todo-add.component';
import { TodoEditComponent } from './components/todo-edit/todo-edit.component';
import { AuthGaurdService } from './services/auth-gaurd.service';
import { LogoutComponent } from './components/logout/logout.component';
import { LoginComponent } from './components/login/login.component';

const routes: Routes = [
  { path: 'todo-list', component: TodoComponent ,canActivate:[AuthGaurdService]},
  { path: 'todo-add', component: TodoAddComponent ,canActivate:[AuthGaurdService] },
  { path: 'todo-edit/:id', component: TodoEditComponent ,canActivate:[AuthGaurdService]},
  { path: '', component: TodoComponent,canActivate:[AuthGaurdService] },
  { path: 'login', component: LoginComponent },
  { path: 'logout', component: LogoutComponent,canActivate:[AuthGaurdService] }
];

@NgModule({
  imports: [
    RouterModule.forRoot(routes)
  ],
  exports: [RouterModule]
})
export class AppRoutingModule { }

All the routes are guarded by auth guard service. AuthGuardService checks ,if user is logged in to the application and then only it activates those routes configured in app-routing.module.ts .

AuthGuardService has canActivate() method which returns true if user is already logged into the application. If user is not logged into the application then it returns false and redirect him to login page.

import { Injectable } from '@angular/core';
import { Router, ActivatedRouteSnapshot, RouterStateSnapshot, CanActivate } from '@angular/router';
import { AuthenticationService } from './authentication.service';

@Injectable({
  providedIn: 'root'
})
export class AuthGaurdService implements CanActivate {

  constructor(private router: Router,
    private authService: AuthenticationService) { }

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
    if (this.authService.isUserLoggedIn())
      return true;

    this.router.navigate(['login']);
    return false;
  }
}

Step 5: Authentication and Todo service (Service Layer)

AuthenticationService (authentication.service.ts) – It handles user authentication into the application. It has authenticate( username, password ) method which receives username and password entered on login page and authenticate user using spring basic authentication method.

Whenever you hit webservice , SecurityConfig.java comes into picture. If you remember, we have configured JWT security in spring boot application created earlier . When we hit todo service then every the time we are authenticated against spring boot JWT security. We need to pass authorization header all the time while hitting webservice from UI. Authorization header contains user credentials and JSON Web Token which has some expiry value upto which we can make request to TODO API.

Also it stores user information in session for checking user logged in status.

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { map } from 'rxjs/operators';

export class User{
  constructor(
    public status:string,
     ) {}
  
}

export class JwtResponse{
  constructor(
    public jwttoken:string,
     ) {}
  
}

@Injectable({
  providedIn: 'root'
})
export class AuthenticationService {
  
  constructor(private httpClient: HttpClient){
  }

  authenticate(username, password) {
    return this.httpClient.post<any>('http://localhost:8081/authenticate',{username,password}).pipe(
     map(
       userData => {
        sessionStorage.setItem('username',username);
        let tokenStr= 'Bearer '+userData.token;
        sessionStorage.setItem('token', tokenStr);
        return userData;
       }
     )

    );
  }

  isUserLoggedIn() {
    let user = sessionStorage.getItem('username')
    console.log('Is User Logged in: '+ !(user === null))
    return !(user === null)
  }

  logOut() {
    sessionStorage.removeItem('username')
  }
}

We also have TodoService (todo.service.ts) to perform various operations on Todo information.

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable, of, throwError } from 'rxjs';
import { map, catchError, tap, retry } from 'rxjs/operators';
import { Todo } from './../domain/Todo';

@Injectable({
  providedIn: 'root'
})
export class TodoService {

  endpoint = 'http://localhost:8081/api';

  username = 'myjavablog';
  password = 'password';

  constructor(private httpClient: HttpClient) {
  }

  // Http Options
  httpOptions = {
    headers: new HttpHeaders({
      'Content-Type': 'application/json'
    })
  }
  
  public deleteTodo(todoId) {

    const headers = new HttpHeaders({ Authorization: 'Bearer ' + btoa(this.username + ':' + this.password) });
    return this.httpClient.delete<Todo>("http://localhost:8081/api/todo" + "/" + todoId, { headers });
  }

  public createTodo(todo) {

    const headers = new HttpHeaders({ Authorization: 'Bearer ' + btoa(this.username + ':' + this.password) });
    return this.httpClient.post<Todo>("http://localhost:8081/api/todo", todo, { headers });
  }

  // To Get List Of Todos
  getTodoList(): Observable<any> {
    
    const headers = new HttpHeaders({ Authorization: 'Bearer ' + btoa(this.username + ':' + this.password) });
    return this.httpClient.get<Todo[]>('http://localhost:8081/api/todos', { headers });
  }

  // HttpClient API get() method => Fetch Todo
  getTodo(id): Observable<Todo> {

    const headers = new HttpHeaders({ Authorization: 'Bearer ' + btoa(this.username + ':' + this.password) });
    return this.httpClient.get<Todo>(this.endpoint + '/todos/' + id, { headers });
  }
  
  // HttpClient API put() method => Update Todo
  updateTodo(id, todo): Observable<Todo> {
    
    const headers = new HttpHeaders({ Authorization: 'Bearer ' + btoa(this.username + ':' + this.password) });
    return this.httpClient.put<Todo>(this.endpoint + '/todo' , JSON.stringify(todo), { headers });
      
  }
}

You can download source code for this application from below link –

Step 6: Run the application

ng serve

Login page

Login page

Home page

Home Page
Generated Token during login

Add todo –

Add Todo

Securing Angular 7 application with Spring Boot Basic Security

We need to configure users and their roles in in separate configuration file. We are creating two projects here –

In this article , i will take you through all the steps to secure your angular application with spring boot basic security. Using Spring boot basic security , we can provide in memory authentication and authorization to our application.

  1. Spring boot basic security application – This will handle the authentication and authorization for our UI application.
  2. UI for Todo manager in angular – This is the Todo manager application which will leverage the basic spring boot security feature.

Part 1: Spring boot basic security application

In this part , we will be creating a simple spring boot application which provides basic security. Its basically a RESTful webservice which has endpoints to access and modify Todos information. To access the Todo information through API , user needs to authenticate himself. Below configuration enables basic security.

SecurityConfig.java

package com.myjavablog;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable().
                authorizeRequests().antMatchers(HttpMethod.OPTIONS, "/**").permitAll().anyRequest().authenticated()
                .and().httpBasic();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("myjavablog").password("{noop}secure").roles("USER");
    }
}

Below is the Rest controller class (TodoController.java)-

package com.myjavablog.controller;

import com.myjavablog.model.Todo;
import com.myjavablog.model.User;
import com.myjavablog.repository.TodoRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;

@CrossOrigin(origins = "http://localhost:4200")
@RestController
@RequestMapping("/api")
public class TodoController {

    //@Autowired
    //private TodoRepository todoRepository;

    static List<Todo> list = new ArrayList<>();

    @GetMapping(produces = "application/json")
    @RequestMapping({ "/validateLogin" })
    public User validateLogin()
    {
        return new User("User successfully authenticated");
    }

    @GetMapping(produces = "application/json")
    @RequestMapping("/todos")
    public List<Todo> getTodos(){
        return list;
    }

    TodoController(){

        list.add(new Todo(1l,"Badminton", "Badminton at 6 am", "Pending"));
        list.add(new Todo(2l,"Cricket", "Cricket at 7 am", "Pending"));
        list.add(new Todo(3l,"Football", "Football at 8 am", "Pending"));
        list.add(new Todo(4l,"Cards", "Cards at 6 am", "Pending"));
        list.add(new Todo(5l,"TT", "TT at 6 am", "Completed"));
        list.add(new Todo(6l,"Golf", "Golf at 6 am", "Pending"));
        list.add(new Todo(7l,"Running", "Running at 6 am", "Pending"));
        list.add(new Todo(8l,"Walking", "Walking at 6 am", "Pending"));
        list.add(new Todo(9l,"Swimming", "Swimming at 6 am", "Completed"));
        list.add(new Todo(10l,"Reading", "Reading at 6 am", "Pending"));

        //return list;
    }

    @GetMapping("/todo/{id}")
    public Todo getTodo(@PathVariable Long id)
    {
        //return todoRepository.findById(id);

        for(Todo todo : list){

            if(todo.getId() == id){
                return todo;
            }
        }

        return null;
    }

    @DeleteMapping("/todo/{id}")
    public boolean deleteTodo(@PathVariable Long id){
        //todoRepository.deleteById(id);

        for(Todo todo : list){

            if(todo.getId() == id){
                list.remove(todo);
            }
        }

        return true;
    }

    @PostMapping("/todo")
    public Todo createTodo(@RequestBody Todo todo){

        list.add(todo);
        return todo;
        //return todoRepository.save(todo);
    }

    @PutMapping("/todo")
    public Todo updateTodo(@RequestBody Todo todo){


        for(Todo t : list){

            if(todo.getId() == t.getId()){
                list.remove(t);
                list.add(todo);
                return todo;
            }
        }

        return null;
        //return todoRepository.save(todo);
    }
}

Source code can be downloaded from below link –

Part 2: UI for Todo manager in angular 7

All the REST service calls are authenticated and authorized using the spring boot basic security. Before calling todo services , we need to pass authorization header with all requests from UI. All our requests to REST calls are intercepted encoded by base 64 encoding and then passed to REST API.

In basic security we pass on base 64 encoded string of username and password to server as authorization header in below format –

Authorization Header = “Basic” + Base64Encoder(username:password)

Step 1: Create new angular application

Refer below post for creating new angular application –

Angular Installation and Setup

Step 2: Create modules for material and primeng components

Create two modules for material(material.module.ts) and primeng( primeng.module.ts ) to define all the related components required in application. These two modules are also required to be imported in main module (app.module.ts)

Please refer below link for primeng and material configuration –

CRUD Operations using primeng datatable and Material Design

Step 3: Create components (Presentation layer)

Create components named header, footer, login,logout and todo components for Todo Manager application.

Todo manager application shows all todos in primeng datatable . Also we are allowed to perform CRUD operations on all todos. All CRUD operations are done in todo component as below –

Todo component –

  • components\todo\todo.component.html
  • components\todo\todo.component.ts

Step 4: Add the routing for application (Application Navigation/Routing)

We have to create a route for the application navigation. Below file contains routing configuration –

  • src\app\app-routing.module.ts
import { NgModule, ViewChildren } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { TodoComponent } from './components/todo/todo.component';
import { TodoAddComponent } from './components/todo-add/todo-add.component';
import { TodoEditComponent } from './components/todo-edit/todo-edit.component';
import { AuthGaurdService } from './services/auth-gaurd.service';
import { LogoutComponent } from './components/logout/logout.component';
import { LoginComponent } from './components/login/login.component';

const routes: Routes = [
  { path: 'todo-list', component: TodoComponent ,canActivate:[AuthGaurdService]},
  { path: 'todo-add', component: TodoAddComponent ,canActivate:[AuthGaurdService] },
  { path: 'todo-edit/:id', component: TodoEditComponent ,canActivate:[AuthGaurdService]},
  { path: '', component: TodoComponent,canActivate:[AuthGaurdService] },
  { path: 'login', component: LoginComponent },
  { path: 'logout', component: LogoutComponent,canActivate:[AuthGaurdService] }
];

@NgModule({
  imports: [
    RouterModule.forRoot(routes)
  ],
  exports: [RouterModule]
})
export class AppRoutingModule { }

All the routes are guarded by auth guard service. AuthGuardService checks ,if user is logged in to the application and then only it activates those routes configured in app-routing.module.ts .

AuthGuardService has canActivate() method which returns true if user is already logged into the application. If user is not logged into the application then it returns false and redirect him to login page.

import { Injectable } from '@angular/core';
import { Router, ActivatedRouteSnapshot, RouterStateSnapshot, CanActivate } from '@angular/router';
import { AuthenticationService } from './authentication.service';

@Injectable({
  providedIn: 'root'
})
export class AuthGaurdService implements CanActivate {

  constructor(private router: Router,
    private authService: AuthenticationService) { }

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
    if (this.authService.isUserLoggedIn())
      return true;

    this.router.navigate(['login']);
    return false;
  }
}

Step 5: Authentication and Todo service (Service Layer)

AuthenticationService (authentication.service.ts) – It handles user authentication into the application. It has authenticate( username, password ) method which receives username and password entered on login page and authenticate user using spring basic authentication method.

Whenever you hit webservice , SecurityConfig.java comes into picture. If you remember, we have configured basic security in spring boot application created earlier . When we hit todo service then all the time we are authenticated against spring boot basic security. We need to pass authorization header all the time while hitting webservice from UI.

Also it stores user information in session for checking user logged in status.

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { map } from 'rxjs/operators';

export class User {
  constructor(
    public status: string,
  ) { }
}

@Injectable({
  providedIn: 'root'
})
export class AuthenticationService {
  
  constructor(private httpClient: HttpClient){
  }

  authenticate(username, password) {
    const headers = new HttpHeaders({ Authorization: 'Basic ' + btoa(username + ':' + password) });
    return this.httpClient.get<User>('http://localhost:8081/api/validateLogin', { headers }).pipe(
      map(
        userData => {
          sessionStorage.setItem('username', username);
          return userData;
        }
      )

    );
  }

  isUserLoggedIn() {
    let user = sessionStorage.getItem('username')
    console.log(!(user === null))
    return !(user === null)
  }

  logOut() {
    sessionStorage.removeItem('username')
  }
}

We also have TodoService (todo.service.ts) to perform various operations on Todo information.

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable, of, throwError } from 'rxjs';
import { map, catchError, tap, retry } from 'rxjs/operators';
import { Todo } from './../domain/Todo';

@Injectable({
  providedIn: 'root'
})
export class TodoService {

  endpoint = 'http://localhost:8081/api';

  username = 'myjavablog';
  password = 'secure';

  constructor(private httpClient: HttpClient) {
  }

  // Http Options
  httpOptions = {
    headers: new HttpHeaders({
      'Content-Type': 'application/json'
    })
  }
  
  public deleteTodo(todoId) {

    const headers = new HttpHeaders({ Authorization: 'Basic ' + btoa(this.username + ':' + this.password) });
    return this.httpClient.delete<Todo>("http://localhost:8081/api/todo" + "/" + todoId, { headers });
  }

  public createTodo(todo) {

    const headers = new HttpHeaders({ Authorization: 'Basic ' + btoa(this.username + ':' + this.password) });
    return this.httpClient.post<Todo>("http://localhost:8081/api/todo", todo, { headers });
  }

  // To Get List Of Todos
  getTodoList(): Observable<any> {
    
    const headers = new HttpHeaders({ Authorization: 'Basic ' + btoa(this.username + ':' + this.password) });
    return this.httpClient.get<Todo[]>('http://localhost:8081/api/todos', { headers });
  }

  // HttpClient API get() method => Fetch Todo
  getTodo(id): Observable<Todo> {

    const headers = new HttpHeaders({ Authorization: 'Basic ' + btoa(this.username + ':' + this.password) });
    return this.httpClient.get<Todo>(this.endpoint + '/todos/' + id, { headers });
  }
  
  // HttpClient API put() method => Update Todo
  updateTodo(id, todo): Observable<Todo> {
    
    const headers = new HttpHeaders({ Authorization: 'Basic ' + btoa(this.username + ':' + this.password) });
    return this.httpClient.put<Todo>(this.endpoint + '/todo' , JSON.stringify(todo), { headers });
      
  }
}

You can download source code for this application from below link –

Step 6: Run the application

ng serve

Login page

Home page

Add todo –

Angular Forms – Template Driven and Reactive

Forms are the mainstay of business applications. You use forms to log in, submit a help request, place an order, book a flight, schedule a meeting, and perform countless other data-entry tasks. Improve overall data quality by validating user input for accuracy and completeness.

Code for this example can be downloaded from below links –

There are two types of forms in Angular.

  1. Template Driven Forms
  2. Reactive Forms

Template Driven Forms

In this kind of form, we can write the forms in Angular template syntax with form syntax directives.

Following are the steps to build template driven forms.

  1. Create the component that controls the form.
  2. Create a template with the initial form layout.
  3. Bind data properties to each form control using the two-way data-binding syntax.
  4. Add an attribute to each form-input control.
  5. Add custom CSS to provide visual feedback.
  6. Show and hide validation-error messages.
  7. Handle form submission with ngSubmit.
  8. Disable the form’s Submit button until the form is valid.

Reactive Forms

We have used Reactive Forms to add Todo’s in our example in previous article. Reactive forms is an Angular technique for creating forms in a reactive style. Angular reactive forms facilitate a reactive style of programming that favors explicit management of the data flowing between a non-UI data model (typically retrieved from a server) and a UI-oriented form model that retains the states and values of the HTML controls on the screen. Reactive forms offer the ease of using reactive patterns, testing, and validation.

In continuation with previous post on CRUD operations, we had created a form to add Todo’s into the system. There we used reactive forms as shown below –

todo-add.component.html

<div id="addTodo" *ngIf="displayAddTodo">
  <form [formGroup]="formGroup" novalidate (ngSubmit)="addTodo()">
    <table>
      <tr>
        <td colspan="2">
          <mat-form-field>
            <input formControlName="name" matInput placeholder="Task Name">
          </mat-form-field>
          <mat-error>
            <span *ngIf="!formGroup.get('name').valid && formGroup.get('name').touched">Please enter Task
              name</span>
          </mat-error>
        </td>
      </tr>
      <tr>
        <td colspan="2">
          <mat-form-field>
            <input formControlName="desc" matInput placeholder="Description">
          </mat-form-field>
          <mat-error>
            <span *ngIf="!formGroup.get('desc').valid && formGroup.get('desc').touched">Please enter Description
            </span>
          </mat-error>
        </td>
      </tr>
      <tr>
        <td colspan="2">
          <mat-form-field>
            <mat-label>Status</mat-label>
            <mat-select formControlName="status">
              <mat-option value="Pending">Pending</mat-option>
              <mat-option value="Cancelled">Cancelled</mat-option>
              <mat-option value="Done">Done</mat-option>
            </mat-select>
          </mat-form-field>
          <mat-error>
            <span *ngIf="!formGroup.get('status').valid && formGroup.get('status').touched">Please enter status</span>
          </mat-error>
        </td>
      </tr>

      <tr>
        <td colspan="2" class="content-center">
          <button mat-raised-button color="accent" [disabled]="!formGroup.valid" (onClick)="addTodo($event)">Submit</button>
              
          <p-button class="btnAdd" label="BACK" (onClick)="goBack()"></p-button>

        </td>
      </tr>
      <tr>
        <td></td>
      </tr>
    </table>
  </form>
  <br>

  <!-- <p-button class="btnAdd" label="BACK" routerLink="/home/add-bcd/nar"></p-button> -->
</div>

First, we need to import some of the modules from the @angular/forms.

  1. FormGroup – This groups the form elements and access their values.
  2. FormBuilder – We have used form builder to handle all the validation.
  3. Validators –  Assigns Validation rules to the Form Object. Also, we need have imported ReactiveFormsModule  in  app.module.ts file.

todo-add.component.ts

import { Component, OnInit, Output, EventEmitter, Input } from '@angular/core';
import { FormBuilder, Validators, FormGroup } from '@angular/forms';
import { Router } from '@angular/router';
import { TodoService } from './../../services/todo.service';
import { NotifierService } from 'angular-notifier';

@Component({
  selector: 'todo-add',
  templateUrl: './todo-add.component.html',
  styleUrls: ['./todo-add.component.css']
})
export class TodoAddComponent implements OnInit {

  formGroup: FormGroup;

  @Output() valueChange = new EventEmitter();
  displayAddTodo: boolean;

  @Input() todo = { name: '', desc: '', status: '' };

  constructor(private formBuilder: FormBuilder, private router: Router, private todoService: TodoService,
    private notifier: NotifierService) { }

  ngOnInit() {
    this.displayAddTodo = true;
    this.initializeTodoForm();
  }

  addTodo() {
    if (this.formGroup.valid) {
      let todo = this.formGroup.value;
      console.log("Todo data " + todo);
      this.todoService.createTodo(todo).subscribe((data: {}) => {
        //this.router.navigate(['/todo-list']);
        this.notifier.notify("success","Todo added successfully");
      })
    }
  }

  initializeTodoForm() {
    this.formGroup = this.formBuilder.group({
      name: ['', [Validators.required]],
      desc: ['', [Validators.required]],
      status: ['', [Validators.required]]
    });
  }

  goBack(): void {
    this.displayAddTodo = false;
    console.log("Back clicked= " + this.displayAddTodo);
    this.valueChange.emit(this.displayAddTodo);
  }
}

We have used form builder (private formBuilder: FormBuilder) to handle all the validation. So in that constructor, we are creating a form with the validation rules.

formGroup: FormGroup – This object is used to access form elements .

Consuming Restful API in angular

In continuation to our previous example on CRUD Operations using primeng datatable and Material Design, we will now look at how to call REST APIs using angular.

Step 1: REST API

We have our REST API developed using java. Below is the code which exposes TODO services to end users. It supports GET,POST,PUT,DELETE operations on resources.

package com.myjavablog.controller;

import com.myjavablog.entity.Todo;
import com.myjavablog.entity.User;
import com.myjavablog.repository.TodoRepository;
import com.myjavablog.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Optional;

@CrossOrigin
@RestController
@RequestMapping("/api")
public class TodoController {

    @Autowired
    private TodoRepository todoRepository;

    @GetMapping("/todos")
    public List<Todo> getTodos(){
        return todoRepository.findAll();
    }

    @GetMapping("/todo/{id}")
    public Optional<Todo> getTodo(@PathVariable Long id){
        return todoRepository.findById(id);
    }

    @DeleteMapping("/todo/{id}")
    public boolean deleteTodo(@PathVariable Long id){
        todoRepository.deleteById(id);
        return true;
    }

    @PostMapping("/todo")
    public Todo createTodo(@RequestBody Todo todo){
        return todoRepository.save(todo);
    }

    @PutMapping("/todo")
    public Todo updateTodo(@RequestBody Todo todo){
        return todoRepository.save(todo);
    }

}

Entire code for this Todo REST API can be downloaded from below github link –

Step 2: How to call REST API from Angular

As we have seen in my previous post , we have written a service in angular to call the REST api’s . Below is the code to call the REST API from angular-

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable, of, throwError } from 'rxjs';
import { map, catchError, tap, retry } from 'rxjs/operators';
import { Todo } from './../domain/Todo';

@Injectable({
  providedIn: 'root'
})
export class TodoService {

  endpoint = 'http://localhost:8081/api';

  constructor(private http: HttpClient) {
  }

  // Http Options
  httpOptions = {
    headers: new HttpHeaders({
      'Content-Type': 'application/json'
    })
  }

  // To Get List Of Todos
  getTodoList(): Observable<any> {
    return this.http.get(this.endpoint + '/todos')
      .pipe(
        retry(1),
        catchError(this.handleError)
      );
  }

  // HttpClient API get() method => Fetch Todo
  getTodo(id): Observable<Todo> {
    return this.http.get<Todo>(this.endpoint + '/todos/' + id)
      .pipe(
        retry(1),
        catchError(this.handleError)
      )
  }

  // HttpClient API post() method => Create Todo
  createTodo(todo): Observable<Todo> {
    return this.http.post<Todo>(this.endpoint + '/todo', JSON.stringify(todo), this.httpOptions)
      .pipe(
        retry(1),
        catchError(this.handleError)
      )
  }

  // HttpClient API put() method => Update Todo
  updateTodo(id, todo): Observable<Todo> {
    return this.http.put<Todo>(this.endpoint + '/todo' , JSON.stringify(todo), this.httpOptions)
      .pipe(
        retry(1),
        catchError(this.handleError)
      )
  }

  // HttpClient API delete() method => Delete Todo
  deleteTodo(id):Observable<Todo[]> {
    console.log("Delete id "+ id);
    return this.http.delete<Todo[]>(this.endpoint+ '/todo/' + id);

  }

  // Error handling 
  handleError(error) {
    let errorMessage = '';
    if (error.error instanceof ErrorEvent) {
      // Get client-side error
      errorMessage = error.error.message;
    } else {
      // Get server-side error
      errorMessage = `Error Code: ${error.status}\nMessage: ${error.message}`;
    }
    window.alert(errorMessage);
    return throwError(errorMessage);
  }
}

We are injecting private http: HttpClient object which is required to make REST API calls. I have hosted REST api on endpoint = ‘http://localhost:8081/api’ , now this endpoint is used to make all rest calls.

Here for all REST calls ,we are returning Observable objects. These methods are getting called from components where these returned objects gets subscribed.Below is the component from which this TodoService is getting called –

import { Component, OnInit } from '@angular/core';
import { TodoService } from 'src/app/services/todo.service';
import { Router } from '@angular/router';
import { map, catchError, tap, retry } from 'rxjs/operators';
import { NotifierService } from 'angular-notifier';
import { Todo } from 'src/app/domain/Todo';
import { SelectItem } from 'primeng/primeng';

@Component({
  selector: 'todo-list',
  templateUrl: './todo.component.html',
  styleUrls: ['./todo.component.css']
})
export class TodoComponent implements OnInit {
  cols: any[];
  todos: Todo[];
  displayedColumns: string[] = ['Task Name', 'Task Description', 'Status', 'action'];

  displayTodoList = true;
  displayTodoAdd = false;
  displayTodoEdit = false;

  constructor(private todoService: TodoService, private router: Router, private notifier: NotifierService) {
  }

  ngOnInit() {
    this.displayTodoList = true;
    this.displayTodoAdd = false;
    this.displayTodoEdit = false;

    console.log("From Init = " + this.displayTodoList + "  " + this.displayTodoAdd);
    this.getTodoList().subscribe((data) => { this.todos = data });

    this.cols = [
      { field: 'name', header: 'Task Name' },
      { field: 'desc', header: 'Task Description' },
      { field: 'status', header: 'Status' },
      { field: 'action', header: 'Action' }
    ];

    this.statusValues = [
      { label: 'Done', value: 'Done' },
      { label: 'Pending', value: 'Pending' },
      { label: 'Cancelled', value: 'Cancelled' }
    ];
  }

  // To Get List Of Todos
  getTodoList() {
    return this.todoService.getTodoList();
  }

  // To Get Todo
  getTodo(todoId) {
    return this.todoService.getTodo(todoId);
  }

  // To Edit Todo
  editTodo(todoId) {
    this.displayTodoList = false;
    this.displayTodoEdit = true;
    this.router.navigate([`/todo-edit/${todoId}`]);
  }

  //Delete Todo
  deleteTodo(todoId) {
    console.log("Delete id" + todoId);
    this.todoService.deleteTodo(todoId).subscribe((data) => {
      console.log("success");
      this.notifier.notify("success", "Task deleted successfully!!");
    });
    this.ngOnInit();
    this.router.navigate([`/`]);
  }

  //add Todo
  addTodo() {
    console.log("Before = " + this.displayTodoList + "  " + this.displayTodoAdd);
    this.displayTodoList = false;
    this.displayTodoAdd = true;
    console.log("After =" + this.displayTodoList + "  " + this.displayTodoAdd);
  }

  hideTodoAdd(event) {
    console.log("Event emiited " + event);
    this.displayTodoList = true;
    this.displayTodoAdd = event;
  }

  clonedTodos: { [s: string]: Todo; } = {};
  statusValues: SelectItem[];

  onRowEditInit(todo: Todo) {
    this.clonedTodos[todo.id] = { ...todo };
  }

  onRowEditSave(todo: Todo) {
    this.todoService.updateTodo(todo.id, todo).subscribe((data) => {
      console.log("success");
      this.notifier.notify("success", "Task updated successfully!!");
    });
  }

  onRowEditCancel(todo: Todo, index: number) {
    this.todos[index] = this.clonedTodos[todo.id];
    delete this.clonedTodos[todo.id];
  }
}

We have injected private todoService: TodoService via constructor and called its methods from TodoComponent .

What is observable and subscriber?

Observables – They provide support for passing messages between publishers and subscribers in your application. Observables offer significant benefits over other techniques for event handling, asynchronous programming, and handling multiple values.

Observables are declarative—that is, you define a function for publishing values, but it is not executed until a consumer subscribes to it. The subscribed consumer then receives notifications until the function completes, or until they unsubscribe.

  // To Get List Of Todos
  getTodoList(): Observable<any> {
    return this.http.get(this.endpoint + '/todos')
      .pipe(
        retry(1),
        catchError(this.handleError)
      );
  }

Subscribe – As a publisher, you create an Observable instance that defines a subscriber function. This is the function that is executed when a consumer calls the subscribe() method. The subscriber function defines how to obtain or generate values or messages to be published.

To execute the observable you have created and begin receiving notifications, you call its subscribe() method, passing an observer. This is a JavaScript object that defines the handlers for the notifications you receive. The subscribe() call returns a Subscription object that has an unsubscribe() method, which you call to stop receiving notifications.

this.getTodoList().subscribe((data) => { this.todos = data });

Code for this example can be downloaded from below links –

CRUD Operations using primeng datatable and Material Design

In this post , we are going to use PrimeNG which provides rich set of open source native Angular UI components and Angular Material Design components. Using these two UI libraries , we will built a application to perform CRUD operations.

Code for this example can be downloaded from below links –

Front End Code

Backend Code

Step 1: Install primeng

https://www.primefaces.org/primeng/#/setup

This package provides us lot of inbuilt UI components to design the User interface as per our requirements. We have created CustomPrimengModule which will have all the primeng components dependencies defined in it. We are using these primeng modules by importing CustomPrimengModule in main app module i.e. aap.module.ts file.

Step 2: Install Angular material

https://material.angular.io/guide/getting-started

Angular Material is a UI component library forAngular JS developers by google. Angular Material components help in constructing attractive, consistent, and functional web pages and web applications while adhering to modern web design principles like browser portability, device independence, and graceful degradation.

I have created CustomMaterialModule which will have all the material components dependencies defined in it. We are using these primeng modules by importing CustomMaterialModule in main app module i.e. aap.module.ts file. Also we need to make one entry for importing styles for material design theme – @import “../node_modules/@angular/material/prebuilt-themes/deeppurple-amber.css”;

Step 3: Define Reactive forms module

I have also defined ReactiveFormsModule and AppRoutingModule which are required for creating forms and routing.

Step 4: Install App notifications Module

https://www.npmjs.com/package/angular-notifier

We are also using NotifierModule to show the notifications in application. For this , we need to import NotifierModule in app.module.ts. Also we need to make one entry for importing styles for notifications – @import “~angular-notifier/styles”;

Step 5 : Create the components/Services/Models required for application

  • Components:

ng g c components/todo –main=app

ng g c components/todo-add –main=app

ng g c components/todo-edit –main=app

  • Services:

ng g s services/todo

  • Model:

Create a typescript file Todo.ts

Step 6: Write the component to perform CRUD operations

src\app\components\todo\todo.component.html

This is the view part which displays primeng data table providing features for sorting, pagination,inline row editing, Delete, Add row etc.

 <div id="list" *ngIf="displayTodoList">
  <p-table [columns]="cols" [value]="todos" sortField="status" sortMode="single" [paginator]="true" [rows]="10"
    [globalFilterFields]="['status','desc']" dataKey="name" editMode="row">
    <ng-template pTemplate="caption">
      List of Todo Tasks
      <p-button class="btnAdd" label="ADD" (onClick)="addTodo()"></p-button>
    </ng-template>
    <ng-template pTemplate="header" let-columns>
      <tr>
        <th *ngFor="let col of columns" [pSortableColumn]="col.field">
          {{col.header}}
          <p-sortIcon [field]="col.field"></p-sortIcon>
        </th>
      </tr>
    </ng-template>

    <ng-template pTemplate="body" let-todo let-editing="editing" let-ri="rowIndex">

      <tr [pEditableRow]="todo">
        <td>
          <p-cellEditor>
            <ng-template pTemplate="input">
              <input pInputText type="text" [(ngModel)]="todo.name">
            </ng-template>
            <ng-template pTemplate="output">
              {{todo.name}}
            </ng-template>
          </p-cellEditor>
        </td>
        <td>
          <p-cellEditor>
            <ng-template pTemplate="input">
              <input pInputText type="text" [(ngModel)]="todo.desc">
            </ng-template>
            <ng-template pTemplate="output">
              {{todo.desc}}
            </ng-template>
          </p-cellEditor>
        </td>
        <td>
          <p-cellEditor>
            <ng-template pTemplate="input">
              <p-dropdown [options]="statusValues" [(ngModel)]="todo.status" [style]="{'width':'100%'}"></p-dropdown>
            </ng-template>
            <ng-template pTemplate="output">
              {{todo.status}}
            </ng-template>
          </p-cellEditor>
        </td>
        <td style="text-align:center">
          <p-button class="btnAdd" icon="pi pi-trash" class="ui-button-info" (onClick)="deleteTodo(todo.id)"></p-button>
             
          <button *ngIf="!editing" pButton type="button" pInitEditableRow icon="pi pi-pencil" class="ui-button-info"
            (click)="onRowEditInit(todo)"></button>
          <button *ngIf="editing" pButton type="button" pSaveEditableRow icon="pi pi-check" class="ui-button-success"
            style="margin-right: .5em" (click)="onRowEditSave(todo)"></button>
          <button *ngIf="editing" pButton type="button" pCancelEditableRow icon="pi pi-times" class="ui-button-danger"
            (click)="onRowEditCancel(todo, ri)"></button>

        </td>
      </tr>
    </ng-template>

    <ng-template pTemplate="summary">
      There are {{todos?.length}} todo tasks
    </ng-template>

  </p-table>
</div>
<todo-add *ngIf="displayTodoAdd" (valueChange)='hideTodoAdd($event)'></todo-add>
<!-- <router-outlet></router-outlet> -->

src\app\components\todo\todo.component.ts

This is a typescript file which has implementation for CRUD operations on primeng datatable. It uses TodoService to perform CRUD operations on data using REST webservice –

import { Component, OnInit } from '@angular/core';
import { TodoService } from 'src/app/services/todo.service';
import { Router } from '@angular/router';
import { map, catchError, tap, retry } from 'rxjs/operators';
import { NotifierService } from 'angular-notifier';
import { Todo } from 'src/app/domain/Todo';
import { SelectItem } from 'primeng/primeng';

@Component({
  selector: 'todo-list',
  templateUrl: './todo.component.html',
  styleUrls: ['./todo.component.css']
})
export class TodoComponent implements OnInit {
  cols: any[];
  todos: Todo[];
  displayedColumns: string[] = ['Task Name', 'Task Description', 'Status', 'action'];

  displayTodoList = true;
  displayTodoAdd = false;
  displayTodoEdit = false;

  constructor(private todoService: TodoService, private router: Router, private notifier: NotifierService) {
  }

  ngOnInit() {
    this.displayTodoList = true;
    this.displayTodoAdd = false;
    this.displayTodoEdit = false;

    console.log("From Init = " + this.displayTodoList + "  " + this.displayTodoAdd);
    this.getTodoList().subscribe((data) => { this.todos = data });

    this.cols = [
      { field: 'name', header: 'Task Name' },
      { field: 'desc', header: 'Task Description' },
      { field: 'status', header: 'Status' },
      { field: 'action', header: 'Action' }
    ];

    this.statusValues = [
      { label: 'Done', value: 'Done' },
      { label: 'Pending', value: 'Pending' },
      { label: 'Cancelled', value: 'Cancelled' }
    ];
  }

  // To Get List Of Todos
  getTodoList() {
    return this.todoService.getTodoList();
  }

  // To Get Todo
  getTodo(todoId) {
    return this.todoService.getTodo(todoId);
  }

  // To Edit Todo
  editTodo(todoId) {
    this.displayTodoList = false;
    this.displayTodoEdit = true;
    this.router.navigate([`/todo-edit/${todoId}`]);
  }

  //Delete Todo
  deleteTodo(todoId) {
    console.log("Delete id" + todoId);
    this.todoService.deleteTodo(todoId).subscribe((data) => {
      console.log("success");
      this.notifier.notify("success", "Task deleted successfully!!");
    });
    this.ngOnInit();
    this.router.navigate([`/`]);
  }

  //add Todo
  addTodo() {
    console.log("Before = " + this.displayTodoList + "  " + this.displayTodoAdd);
    this.displayTodoList = false;
    this.displayTodoAdd = true;
    console.log("After =" + this.displayTodoList + "  " + this.displayTodoAdd);
  }

  hideTodoAdd(event) {
    console.log("Event emiited " + event);
    this.displayTodoList = true;
    this.displayTodoAdd = event;
  }

  clonedTodos: { [s: string]: Todo; } = {};
  statusValues: SelectItem[];

  onRowEditInit(todo: Todo) {
    this.clonedTodos[todo.id] = { ...todo };
  }

  onRowEditSave(todo: Todo) {
    this.todoService.updateTodo(todo.id, todo).subscribe((data) => {
      console.log("success");
      this.notifier.notify("success", "Task updated successfully!!");
    });
  }

  onRowEditCancel(todo: Todo, index: number) {
    this.todos[index] = this.clonedTodos[todo.id];
    delete this.clonedTodos[todo.id];
  }
}

Step 7: Service Layer – We have injected TodoService through constructor and used it to perform CRUD operations .This service has GET,POST,PUT,DELETE calls to REST endpoints .

src\app\services\todo.service.ts

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable, of, throwError } from 'rxjs';
import { map, catchError, tap, retry } from 'rxjs/operators';
import { Todo } from './../domain/Todo';

@Injectable({
  providedIn: 'root'
})
export class TodoService {

  endpoint = 'http://localhost:8081/api';

  constructor(private http: HttpClient) {
  }

  // Http Options
  httpOptions = {
    headers: new HttpHeaders({
      'Content-Type': 'application/json'
    })
  }

  // To Get List Of Todos
  getTodoList(): Observable<any> {
    return this.http.get(this.endpoint + '/todos')
      .pipe(
        retry(1),
        catchError(this.handleError)
      );
  }

  // HttpClient API get() method => Fetch Todo
  getTodo(id): Observable<Todo> {
    return this.http.get<Todo>(this.endpoint + '/todos/' + id)
      .pipe(
        retry(1),
        catchError(this.handleError)
      )
  }

  // HttpClient API post() method => Create Todo
  createTodo(todo): Observable<Todo> {
    return this.http.post<Todo>(this.endpoint + '/todo', JSON.stringify(todo), this.httpOptions)
      .pipe(
        retry(1),
        catchError(this.handleError)
      )
  }

  // HttpClient API put() method => Update Todo
  updateTodo(id, todo): Observable<Todo> {
    return this.http.put<Todo>(this.endpoint + '/todo' , JSON.stringify(todo), this.httpOptions)
      .pipe(
        retry(1),
        catchError(this.handleError)
      )
  }

  // HttpClient API delete() method => Delete Todo
  deleteTodo(id):Observable<Todo[]> {
    console.log("Delete id "+ id);
    return this.http.delete<Todo[]>(this.endpoint+ '/todo/' + id);

  }

  // Error handling 
  handleError(error) {
    let errorMessage = '';
    if (error.error instanceof ErrorEvent) {
      // Get client-side error
      errorMessage = error.error.message;
    } else {
      // Get server-side error
      errorMessage = `Error Code: ${error.status}\nMessage: ${error.message}`;
    }
    window.alert(errorMessage);
    return throwError(errorMessage);
  }
}

Step 8: Domain Layer – It contains model to hold the todo tasks data.

export interface Todo {
  
    id?;
	name?;
	desc?;
	status?;
}

Step 9: Now we are ready to run the project –

ng serve

Step 10: Screenshots –

Main page with data Grid

Add Task screen

Inline Task Editing screen

Deleting task –

Angular 7 – CRUD Operations

This is very huge post which covers most of the angular concepts , so please be patient and go through it. This post is related to angular CRUD operations using angular AG grid and REST webservices in java. We will go through below concepts while going through these post –

  1. REST API in java
  2. AG Grid in java
  3. Bootstrap Configuration
  4. Notifications service configuration
  5. Reactive forms in angular
  6. Form Validations
  7. Service in angular
  8. Calling REST API using HttpClient
  9. Routing and Navigation

1.REST API in java

We would need to create a REST API which supports CRUD operations on user data as below –

package com.myjavablog.controller;

import com.myjavablog.entity.User;
import com.myjavablog.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Optional;

@CrossOrigin
@RestController
@RequestMapping("/api")
public class UserController {

    @Autowired
    private UserRepository userRepository;

    @GetMapping("/users")
    public List<User> getUsers(){
        return userRepository.findAll();
    }

    @GetMapping("/user/{id}")
    public Optional<User> getUser(@PathVariable Long id){
        return userRepository.findById(id);
    }

    @DeleteMapping("/user/{id}")
    public boolean deleteUser(@PathVariable Long id){
        userRepository.deleteById(id);
        return true;
    }

    @PostMapping("/user")
    public User createUser(@RequestBody User user){
        return userRepository.save(user);
    }

    @PutMapping("/user")
    public User updateUser(@RequestBody User user){
        return userRepository.save(user);
    }

}

This is the controller in java which supports GET,UPDATE,PUT,POST operations on USER data.

You can download the entire code from below Github link –

2. AG Grid in java

Before actually going into angular project, you can go through my older posts on how to create angular project. https://www.myjavablog.com/2019/04/13/angular-installation-and-setup/

Once the project is created you need to install ag-grid support to it. Below packages needs to be installed for the same –

npm i --save ag-grid

You need to import this dependency in app.module.ts by adding below line under imports –

AgGridModule.withComponents(null)

Also you need to add CSS support for grid in styles.css

@import 'ag-grid-community/dist/styles/ag-grid.css';
@import 'ag-grid-community/dist/styles/ag-theme-blue.css

Then create a component using below command –

ng n c user

This will create new user component and create CSS, TS , html files. Add code to html file for grid –

<h2 class="header">Angular 7 AG Grid CRUD Operations Example</h2>
<a href="/addUser"><button class="btn btn-sm btn-success button">Add User</button></a>  
<button class="btn btn-sm btn-primary" (click)="editUser()">Edit User</button>  
<button class="btn btn-sm btn-danger" (click)="deleteUser()">Delete User</button>
<br><br>
<ag-grid-angular style="width: 100%; height: 600px;"
    class="ag-theme-blue"
    (gridReady)="onGridReady($event)"
    [columnDefs]="columnDefs"
    [rowData]="users"
    rowSelection="single"    
    pagination="true"
    paginationPageSize =25
    (selectionChanged)="onSelectionChanged($event)"
    (cellEditingStopped)="onCellEditingStopped($event)"
    (dataChanged)="onrowValueChanged($event)"
    >
</ag-grid-angular>

All the options specified in grid configuration are self explanatory. You also need Typescript file in order to perform CRUD operations . You get this from my github link.

3. Bootstrap Configuration

First install bootstrap by using below npm command –

npm install bootstrap

Then Add bootstrap to angular.json under styles-

"styles": [
              "src/styles.css",
              "node_modules/bootstrap/dist/css/bootstrap.min.css"              
            ],

4. Notifications service configuration

This service is to show the notifications to users. Use below npm command to install –

npm install angular-notifier

Add it into imports in app.module.ts and add custom options as well-

NotifierModule.withConfig( customNotifierOptions )

/**
 * Custom angular notifier options
 */
const customNotifierOptions: NotifierOptions = {
	position: {
		horizontal: {
			position: 'middle',
			distance: 12
		},
		vertical: {
			position: 'top',
			distance: 12,
			gap: 10
		}
	},
	theme: 'material',
	behaviour: {
		autoHide: 5000,
		onClick: false,
		onMouseover: 'pauseAutoHide',
		showDismissButton: true,
		stacking: 4
	},
	animations: {
		enabled: true,
		show: {
			preset: 'slide',
			speed: 300,
			easing: 'ease'
		},
		hide: {
			preset: 'fade',
			speed: 300,
			easing: 'ease',
			offset: 50
		},
		shift: {
			speed: 300,
			easing: 'ease'
		},
		overlap: 150
	}
};

Also you would need to add CSS for notifier in app.component.html file as below –

<link rel="stylesheet" href="https://unpkg.com/[email protected]/styles.css">

5. Reactive forms in angular

Now you need to create user form to add users –

<div class="row">

  <div class="col-md-6 col-md-offset-2">
      <h1><span class="badge badge-light" id="header">Add User</span></h1>
    <form [formGroup]="userForm" (ngSubmit)="onSubmit()">
      
      <div class="form-group">
            <label for="firstName">First Name:</label>
            <input type="text" class="form-control" formControlName="fname" id="fname">
            <div *ngIf="submitted && userForm.controls.fname.errors" class="error">
              <div *ngIf="userForm.controls.fname.errors.required">First name is required</div>
            </div>
      </div>

      <div class="form-group">
          <label for="lastName">Last Name:</label>
          <input type="text" class="form-control" formControlName="lname" id="lname">
          <div *ngIf="submitted && userForm.controls.lname.errors" class="error">
            <div *ngIf="userForm.controls.lname.errors.required">Last name is required</div>
          </div>
      </div>

      <div class="form-group">
        <label for="email">Email address:</label>
        <input type="email" class="form-control" formControlName="email" id="email1">
        <div *ngIf="submitted && userForm.controls.email.errors" class="error">
          <div *ngIf="userForm.controls.email.errors.required">Email is required</div>
        </div>
      </div>

      <div class="form-group">
          <label for="age">Age:</label>
          <input type="text" class="form-control" formControlName="age" id="age1">
          <div *ngIf="submitted && userForm.controls.age.errors" class="error">
            <div *ngIf="userForm.controls.age.errors.required">Age is required</div>
          </div>
      </div>

      <div class="form-group">
          <label for="mobile">Mobile:</label>
          <input type="text" class="form-control" formControlName="mobile" id="mob">
          <div *ngIf="submitted && userForm.controls.mobile.errors" class="error">
            <div *ngIf="userForm.controls.mobile.errors.required">Mobile number is required</div>
          </div>
      </div>

      <button class="btn btn-primary">Submit</button>
      <div *ngIf="invalidLogin" class="error">
        <div>Invalid credentials.</div>
      </div>
    </form>
  </div>

  <a routerLink="/users"><button class="btn btn-sm btn-success button">Back</button></a>
</div>

6. Form Validations

With reactive forms ,you can associate FormGroup and FormBuilder and access the form fields . Using these objects , you can also validate the form fields using angular Validators.

7. Services in Angular

We have to write the service to call the REST APIs and perform CRUD operations as below –

Create service using –

ng g s user

import { Injectable } from '@angular/core';
import { User } from './../model/user';
import {HttpClient} from '@angular/common/http';

@Injectable({
  providedIn: 'root'
})
export class UserService {

  apiUrl:string = "http://localhost:8081/api/";

  constructor(private http : HttpClient) { 
  }

  getUsers() {
    return this.http.get<User[]>(this.apiUrl+'users');
   }

   deleteUser(userId: number){
    return this.http.delete(this.apiUrl+'user/'+userId);
   }

   addUser(user: User){
     console.log(user);
     return this.http.post(this.apiUrl+ 'user/', user );
   }

   editUser(user: User){
    console.log(user);
    return this.http.put(this.apiUrl+ 'user/', user );
  }
 
}

8. Calling REST API using HttpClient

In above service, we are injecting HttpClient in constructor to call the REST API.

9. Routing and Navigation

We would need to provide routing for our application. So specific URI will be served by specific Component. Route configuration is provided in app-routing.module.ts as below –

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { LoginComponent } from './components/login/login.component';
import { UserComponent } from './components/user/user.component';
import { AddUserComponent } from './components/user/add-user/add-user.component';

const routes: Routes = [
  {path:'users',  component:UserComponent},
  {path:'', component:LoginComponent},
  {path:'addUser', component:AddUserComponent},
  {path:'login', component:LoginComponent}
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  

exports: [RouterModule]
})
export class AppRoutingModule { }

You can download the code for this application from below github link –

Now build the application and serve it to the client –

ng build
ng serve

Now the application is ready to access on http://localhost:4200/-

Login screen

Angular ag grid showing all users
Add New User

User Editing
Updated last name and email

User Deleted

Form Validations

Angular Directives

There are mainly two types of directives as below –

Structural Directives

Structural Directives are used for manipulating the DOM elements. You will find an asterisk (*) prefix before the directive. We can take*ngFor and *ngIf as examples here.

Attribute Directives

When it comes to altering the behavior and look of the DOM element, you turn to attribute directives.

  • ngIf
  • ngSwitchCase
  • ngFor
  • ngStyle
  • ngClass

Angular History and Advantages

Angular JS is quite famous javascript framework. It evolved from Angular 1 to recently used Angular 7 version. Below is the detailed version evolution history of angular –

Angular 1:

AngularJS was released in 2010 by Google. Normally AngularJS is also referred as Angular1 by some people. So AngularJS is of version Angular 1.x. This is the only version of AngularJS. Everything was fine but development of ReactJS and its large impact on the world and also the fact it was from Facebook was quite intense. It led to competition between frameworks from two renowned companies.

Angular 2:

So to match the needs Google developed Angular2 which was released in 2016, a complete re-write of AngularJS from same the team which developed AngularJS . To avoid name confusion team went with the same name without JS part. And the difference between AngularJS 1.x and the new Angular was such that it was impossible to update from one to another. So only option was to migrate. Angular2 is based on service/controller model whereas AngularJS was using MVC model. Also it uses TypeScript to build the application in place of JavaScript.

Angular 4:

Then team developed Angular3 but it was skipped and Angular4 was introduced. Angular4 was introduced in 2017 which introduced some new features like Universal Project. Unlike AngularJS and Angular2, Angular4 is compatible with Angular2. This means it is a improved version of Angular2 and not a re-write. Angular4 provides many enhancements in comparison to Angular2. Some of these enhancements are inbuilt Animation Package, ngTemplate,Form Validator attributes , titlecase pipe etc.

Angular 5:

Then Angular5 was released but it was just updated version of Angular4. It has a bunch of additional features and bug fixes like Build Optimizer, HttpClient etc.

Angular 6:

Angular6 is the latest version of angular which was released in 2018. It focuses more on toolchain like with Angular in the future, like: ngAngular Elements, CLI Workspaces, Library Support, Angular Material Starter Components. So these are versions of Angular till date. Angular6 is much faster to its previous versions as it is using Ivy Rendered which is a rendering engine.

Angular 7:

The Angular 7 is escalated between Angular core frameworks, Angular Material a CLI. Angular CLI has now a convenient guide to walk through the creation of the applications. Angular 7 also introduced the concept of the “Bundle Budget” which helps in reducing the bundle size of an Angular app. Angular Material is a UI toolkit, which has modernized the homepage for guidance related to design, components and tooling around for building better user experiences. Angular CDK provides virtual scrolling capabilities with a drag & drop framework.

Advantages Of using Angular –

  • Two-way data binding – AngularJS was built with Model-View-Controller architecture. And the framework synchronized the Model and the View. As the data in the Model changes, the View does too. Two-way data binding allowed engineers to reduce development time as it didn’t require writing additional code to provide continual View and Model synchronization.
  • Directives – This feature actually enabled the HTML extension mentioned above. Directives allowed developers to assign special behaviors to the Document Object Model (DOM), permitting engineers to create dynamic and rich content with HTML.
  • Dependency injection – Dependencies define how different pieces of code interact with each other and how the changes in one component impact the other ones. Usually, dependencies are directly defined in components themselves. So that every change in dependency requires changing components as well. With AngularJS, you could use injectors that defined dependencies as external elements decoupling components from their dependencies. Dependency injection made components more reusable, easier to manage and test.
  • Community – Right from the beginning, AngularJS became extremely popular among engineers. A strong community provided enough training materials, discussions, and third-party tools to embark on using AngularJS as well as find a solution to nearly every arising issue.

Newer versions of angular i.e. Angular 2 plus has components based design as compared to angular 1 which followed MVC flow. Components based architecture provides high reusability of components across the Application.

  • Great performance – Angular2 – doesn’t do deep object comparison. If items are added/removed to/from an array, change detection won’t detect it. The same for object properties as long as they are not directly bound from the view.
  • Reusability – Components of a similar nature are well encapsulated, in other words, self-sufficient. Developers can reuse them across different parts of an application. This is particularly useful in enterprise-scope applications where different systems converge but may have many similar elements like search boxes, date pickers, sorting lists, etc.
  • Readability – Encapsulation also ensures that new developers – who’ve been recently on boarded to a project – can read code better and eventually reach their plateau of productivity faster.
  • Unit Test Friendly – The independent nature of components simplifies unit tests, quality assurance procedures aimed at verifying the performance of the smallest parts of the application units.
  • Maintainability – Components that are easily decoupled from each other can be easily replaced with better implementations. Basically, your engineering team will be more efficient in maintaining and updating the code within the iterative development workflow.
  • Usage of Typescript – The biggest selling point of TypeScript is tooling. It provides advanced autocompletion, navigation, and refactoring. Having such tools is almost a requirement for large projects.

Angular Installation and Setup

In this post , we will see how to install angular environment and create & run first ever angular application –

Prerequisites –

You need to install node.js on your system. You can download node.js from their official website https://nodejs.org/en/

Once you install it on your system,you can check the version of node.js by executing below command on command line –

node -v
v10.15.0

With node.js installation ,you will by default get npm (Node Package Manager). NPM provides the libraries required to run the angular application. Below command gives the version of npm –

npm -v
6.4.1

Now below are the steps to create,build & deploy your first angular application .

Step 1: Install Angular CLI

Angular CLI is Command Line Interface which provides various commands to create , build and deploy application . Below is npm command to install Angular CLI globally –

npm install -g @angular/cli

Step 2: Create a workspace anf first Anguar application

ng new firstApp

This will create a workspace for new project i.e. first-app . It will generate all the initial artifacts. Project structure is as below –

  • src – All source files
  • e2e – End to end test project
  • Configuration files – angular.json, package.json etc.

Step 3: Use of IDE

I personally prefer, Visual Code Studio as IDE for angular project. Its an open source IDE provided by Microsoft.

Step 4: Build and deploy

ng build

This command will build the project and create the artifacts in /dist folder.

ng serve

This command will deploy the build artifacts to nodejs server and serve it to client.

Application can accessed via – http://localhost:4200/

Dockerizing angular application

In this post , we will dockerize a simple application designed in angular 7.

Tools used –

  • Docker Toolbox
  • Visual Code Studio
  • npm

Steps required to dockerize the simple angular application are as below -Go to the folder where you want to create angular project

Step 1: Go to the folder where you want to create angular project

Step 2: You need to first install NodeJS and then angular CLI using below command –

npm install -g @angular/cli

Step 3: Once you install angular CLI package from node package manager, you will be able to execute angular commands on console. With below commands you can create new angular project and build it.

  • Create new angular project –

ng new angular-docker-demo

  • Switch to newly created folder by

cd angular-docker-demo

  • You can run the angular project using belwo command –

ng serve

Running application can be access from – http://localhost:80/

Step 4: Now in this step , we will move towards dockerizing the application created in above steps. For that, you need to create docker file as below –

FROM nginx:1.13.3-alpine

## Remove default code for nginx website
RUN rm -rf /usr/share/nginx/html/*

## Copy all build artifacts in dist folder generated after building project into default nginx public folder
COPY /dist /usr/share/nginx/html

#Expose port 80 of container
EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]

First line in docker file i.e. FROM nginx:1.13.3-alpine will download nginx server from docker hub. NGINX (Pronounced as Engine-X) is an open source, lightweight, high-performance web server or proxy server. We would need this server to host our application.

Second line will remove default NGINX website code present under /usr/share/nginx/html/ folder.

After we build our angular project ,build artifacts will be generated under /dist folder . Third line will copy contents of /dist under
/usr/share/nginx/html/ folder and will serve this web content on browser.

Step 5: Below commands will first build the angular application which is PROD ready. Then build the docker image and run that image.

  • ng build --prod
  • docker build -t angular-docker-demo.
  • docker run -p 8082:80 --name angular-docker-demo angular-docker-demo
Bitnami