Getting Started | Building an Application with Angular
Angular 10 Front-end
In this tutorial We are going build an application Movies to display the movies we will use the query find by title, find by year, find by director and find by actor. we use mongodb database to develope this project. Front-end side is made with Angular 10, HTTPClient & Router.
Angular CLI version (10.1.1)
ng new
The Angular CLI makes it easy to create an application that already works, right out of the box. It already follows our best practices!
ng generate
Generate components, routes, services and pipes with a simple command. The CLI will also create simple test shells for all of these.
ng serve
Easily test your app locally while developing.
$ npm install -g @angular/cli
$ ng new movies
$ cd movies
$ ng serve
Technology
Angular 10
Angular HTTPClient
Angular Router
Project Structure
Install Bootstrap CSS framework
Bootstrap a framework to encourage consistency across internal tools. Before Bootstrap, various libraries were used for interface development, which led to inconsistencies and a high maintenance burden. According to Twitter developer Mark Otto:
Use the following command to install bootstrap in the project.
$ npm install bootstrap --save
Install Pagination
The ngx-pagination offers the simplest yet powerful solution for making pagination in Angular. All hail to its flexibility and responsiveness, customization is pretty handy with ngx-pagination, and yes its is loaded with some beautiful themes too.
Use the following command to install bootstrap in the project.
$ npm install ngx-pagination --save
src/style.css
First of all, we need to create the various entry point CSS files of course. You can just create further scss files at the level where the styles.scss is in your project.
src/style.css
@import '~bootstrap/dist/css/bootstrap.min.css';
table {
font-family: "Lato", "sans-serif";
width: 100%;
}
table.one{
margin-bottom: 3em;
border-collapse: collapse;
}
td {
text-align: center;
width: 10em;
padding: 1em;
}
th {
text-align: center;
padding: 1em;
background-color: #e8503a;
color: white;
}
tr {
height: 1em;
}
table tr:nth-child(even) {
background-color: #eee;
}
table tr:nth-child(odd) {
background-color: #fff;
}
h2 {
color: #8e9195;
font-family: initial;
}
.lds-hourglass {
display: inline-block;
position: relative;
width: 80px;
height: 80px;
}
.lds-hourglass:after {
content: " ";
display: block;
border-radius: 50%;
width: 0;
height: 0;
margin: 8px;
box-sizing: border-box;
border: 32px solid #fff;
}
.loader {
border: 16px solid #f3f3f3;
border-radius: 50%;
border-top: 16px solid #007bff !important;
width: 100px;
height: 100px;
-webkit-animation: spin 2s linear infinite;
animation: spin 2s linear infinite;
margin-left: 100px;
}
@-webkit-keyframes spin {
0% {
-webkit-transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
}
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
Introduction to components and templates
A component controls a patch of screen called a view. For example, individual components define and control each of the following views from the Tour of application tutorial:
You define a component's application logic—what it does to support the view—inside a class. The class interacts with the view through an API of properties and methods.
src/app/app-component.html
<ul class="nav nav-tabs" style="background: #e8503a; color: white;">
<li class="nav-item">
<a class="nav-link" [routerLink]="['/findAllArtistes']">Artistes</a>
</li>
<li class="nav-item">
<a class="nav-link" [routerLink]="['/findAllMovies']">Movies</a>
</li>
<li class="nav-item">
<a class="nav-link" [routerLink]="['/query-movies']">Queries movies</a>
</li>
</ul>
<div style="padding-bottom: 20px;">
<router-outlet></router-outlet>
</div>
Model
Let's create classes by using the following command
$ ng g class ClassName
The purpose of this class is to map the specified fields with the fields of Spring entity class.
src/app/model/Artistes.ts
export class Artistes {
_id: number;
last_name: string;
first_name: string;
birth_data: string;
}
src/app/model/Actor.ts
export class Actor {
_id: number;
role: string;
}
src/app/model/Director.ts
export class Director {
_id: number;
}
src/app/model/Movie.ts
import {Actor} from './Actor';
import {Director} from './Director';
export class Movie {
_id: number;
title: string;
genre: string;
summary: string;
country: string;
actor: Actor;
director[]: Director;
}
Create Data Service
This service will use Angular HTTPClient to send HTTP requests. You can see that its functions includes CRUD operations and finder method.
service/artiste.service.ts
import { Injectable } from '@angular/core';
import {HttpClient} from '@angular/common/http';
import {Observable} from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class ArtisteService {
private baseUrl = "http://localhost:8080";
constructor(private http: HttpClient) { }
findAllArtistes(): Observable<any[]> {
return this.http.get<any[]>(`${this.baseUrl}/findAllArtists`);
}
}
service/movie.service.ts
import { Injectable } from '@angular/core';
import {HttpClient} from '@angular/common/http';
import {Observable} from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class MovieService {
private baseUrl = "http://localhost:8080";
constructor(private http: HttpClient) { }
findAllMovies(): Observable<any[]> {
return this.http.ge<any[]>(`${this.baseUrl}/findAllMovies`);
}
getMovieByDetails(id: string): Observable<any> {
return this.http.get(`${this.baseUrl}/movie/details=${id}`);
}
findMovieId(): Observable<any> {
return this.http.get(`${this.baseUrl}/movie/id`);
}
findMovieYear(): Observable<any[]> {
return this.http.get<any[]>(`${this.baseUrl}/movie/years`);
}
findMovieTitle(): Observable<any> {
return this.http.get(`${this.baseUrl}/movie/title`);
}
findMovieDirectorID(): Observable<any[]> {
return this.http.get<any[]>(`${this.baseUrl}/movie/directoryId`);
}
findMovieActorsId(): Observable<any[]> {
return this.http.get<any[]>(`${this.baseUrl}/movie/actor/id`);
}
findMovieSearch(): Observable<any[]> {
return this.http.get<any[]>(`${this.baseUrl}/movie/search`);
}
findMovieBetweenYear(): Observable<any[]> {
return this.http.get<any[]>(`${this.baseUrl}/movie/between/year`);
}
}
Create Angular Components
As you’ve known before, there are 4 components corresponding to 4 routes defined in AppRoutingModule.
$ ng generate component find-all-artistes
$ ng generate component find-all-movies
$ ng generate component movie-details
$ ng generate component query-movies
Find all artistes component
find-all-artistes.component.ts
import { Component, OnInit } from '@angular/core';
import { Artistes } from '../model/Artistes';
import { ArtisteService } from '../service/artiste.service';
@Component({
selector: 'app-find-all-artistes',
templateUrl: './find-all-artistes.component.html',
styleUrls: ['./find-all-artistes.component.scss']
})
export class FindAllArtistesComponent implements OnInit {
artistes: Artistes[];
spinnerLoad = true;
showTable = false;
allNumber: number;
p = 0;
constructor(private artisteService: ArtisteService) { }
ngOnInit() {
this.artisteService.findAllArtistes().subscribe(data => {
this.artistes = data;
this.spinnerLoad = false;
this.showTable = true;
this.allNumber = this.artistes.length;
});
}
}
find-all-artistes.component.html
<div class="container">
<h2> <i class="fas fa-icons" style='font-size:48px;'></i> All artistes {{allNumber}}</h2><hr>
<div class="loader" *ngIf="spinnerLoad"></div>
<div *ngIf="showTable">
<table class="table table-hover table-bordered">
<tr>
<th>ID</th>
<th>Firstname</th>
<th>Lastname</th>
<th>Birthdate</th>
</tr>
<tr *ngFor="let art of artistes | paginate:{itemsPerPage: 6, currentPage:p} ">
<td>{{art._id}}</td>
<td>{{art.last_name}}</td>
<td>{{art.first_name}}</td>
<td>{{art.birth_date}}</td>
</tr>
</table>
<div id="pagination">
<pagination-controls (pageChange)="p=$event"></pagination-controls>
</div>
</divv>
</div>
Find all movies component
find-all-movies.component.ts
import { Component, OnInit } from '@angular/core';
import {Router} from '@angular/router';
import { MovieService } from '../service/movie.service';
@Component({
selector: 'app-find-all-movies',
templateUrl: './find-all-movies.component.html',
styleUrls: ['./find-all-movies.component.scss'],
})
export class FindAllMoviesComponent implements OnInit {
spinnerLoad = true;
showTable = false;
collection = [];
allNumber: number;
p = 0;
constructor(private movieService: MovieService, private router: Router) {}
ngOnInit() {
this.movieService.findAllMovies().subscribe(data => {
this.collection = data;
this.spinnerLoad = false;
this.showTable = true;
this.allNumber = this.collection.length;
});
}
movieDetails(id: string) {
this.router.navigate(['movieDetails/', id]);
}
}
find-all-movies.component.scss
<div class="container">
<h2><i class="fas fa-video" style='font-size:48px;'></i> All movies <span>{{allNumber}}</span> </h2><hr>
<div class="loader" *ngIf="spinnerLoad"></div>
<div *ngIf="showTable">
<table class="table table-hover table-bordered">
<thead>
<tr>
<th>ID</th>
<th>Title</th>
<th>Genre</th>
<th>Country</th>
<th>Year</th>
<th>Details</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of collection | paginate:{itemsPerPage: 6, currentPage:p}">
<td>{{item._id}}</td>
<td>{{item.title}}</td>
<td>{{item.genre}}</td>
<td>{{item.country}}</td>
<td>{{item.year}}</td>
<td title="More details"><button type="button" class="btn btn-primary" (click)="movieDetails(item._id)">Details</button></td>
</tr>
</tbody>
</table>
<div id="pagination">
<pagination-controls (pageChange)="p=$event"></pagination-controls>
</div>
</div>
</div>
Movies details component
movie-details.component.ts
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Movie } from '../model/Movie';
import { MovieService } from '../service/movie.service';
@Component({
selector: 'app-movie-details',
templateUrl: './movie-details.component.html',
styleUrls: ['./movie-details.component.scss']
})
export class MovieDetailsComponent implements OnInit {
idMovie: string;
movies: Movie[];
movie: Movie = new Movie();
constructor(private movieService: MovieService, private route: ActivatedRoute) { }
ngOnInit() {
this.idMovie = this.route.snapshot.params.idMovie;
this.movieService.getMovieByDetails(this.idMovie).subscribe(data => {
this.movies = data;
this.movies.forEach(movie => {
this.movie = movie;
});
});
}
}
movie-details.component.html
<div class="container">
<div class="jumbotron">
<h1 class="display-4" style="color:#8e9195; font-family: initial;"><i class='fas fa-skiing'></i> Movie details </h1>
<hr>
<br>
<div class="row">
<div class="col-sm-4">
<div class="card text-dark bg-light">
<div class="card-header bg-dark text-center text-light"><h4> Summary </h4></div>
<div class="card-body">
<div class="list-group">
<span *ngIf="movie.summary"> {{movie.summary}}</span>
<span *ngIf="!movie.summary"> No summary </span>
</div>
</div>
<div class="card-footer bg-secondary border-danger text-right">
<a href="#" class="btn btn-info btn-md">home</a>
</div>
</div>
</div>
<div class="col-md-8">
<table class="table table-hover">
<thead class="thead-light">
<tr>
<th>Role</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let s of movie.actors">
<td *ngIf="s.role">{{s.role}}</td>
<td *ngIf="!s.role">No role</td>
</tr>
</tbody>
</table>
</div>
</div>
<br>
<hr style="margin-top: 0px; border: 1px solid #F48989;">
</div>
</div>
Queries movies component
query-movies.component.ts
import { Component, OnInit } from '@angular/core';
import { Movie } from '../model/Movie';
import { MovieService } from '../service/movie.service';
@Component({
selector: 'app-query-movies',
templateUrl: './query-movies.component.html',
styleUrls: ['./query-movies.component.scss'],
})
export class QueryMoviesComponent implements OnInit {
movieId: Movie = new Movie();
years: Movie[];
movieTitle: Movie = new Movie();
movieDirector: Movie[];
movieActorsId: Movie[];
movieSearch: Movie[];
movieBetween: Movie[];
constructor(private movieService: MovieService) {}
ngOnInit() {
this.movieService.findMovieTitle().subscribe((title) => {
this.movieTitle = title;
});
this.movieService.findMovieYear().subscribe((years) => {
this.years = years;
});
this.movieService.findMovieId().subscribe((id) => {
this.movieId = id;
});
this.movieService.findMovieDirectorID().subscribe((director) => {
this.movieDirector = director;
});
this.movieService.findMovieActorsId().subscribe((actors) => {
this.movieActorsId = actors;
});
this.movieService.findMovieSearch().subscribe((search) => {
this.movieSearch = search;
});
this.movieService.findMovieBetweenYear().subscribe((between) => {
this.movieBetween = between;
});
}
}
query-movies.component.html
<div class="container">
<span>Afficher les infos sur le film dont l'id est 2 ?</span>
<table class="table table-hover">
<thead class="thead-light">
<tr>
<th>Id</th>
<th>Role</th>
<th>Title</th>
<th>Genre</th>
<th>Country</th>
<th>Year</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let m of movieId.actors">
<td>{{ movieId._id }}</td>
<td *ngIf="m.role">{{ m.role }}</td>
<td>{{ movieId.title }}</td>
<td>{{ movieId.genre }}</td>
<td>{{ movieId.country }}</td>
<td>{{ movieId.year }}</td>
</tr>
</tbody>
</table>
<hr/>
<span>Lister ts les films produits en 1979 ? </span>
<table class="table table-hover">
<thead class="thead-light">
<tr>
<th>Id</th>
<th>Title</th>
<th>Genre</th>
<th>Country</th>
<th>Year</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let m of years">
<td>{{ m._id }}</td>
<td>{{ m.title }}</td>
<td>{{ m.genre }}</td>
<td>{{ m.country }}</td>
<td>{{ m.year }}</td>
</tr>
</tbody>
</table>
<hr/>
<span>Afficher les infos sur le film dont le title est "Alien" produit en 1979 ? </span>
<table class="table table-hover">
<thead class="thead-light">
<tr>
<th>Id</th>
<th>Title</th>
<th>Genre</th>
<th>Country</th>
<th>Year</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let m of movieTitle.actors">
<td>{{ m._id }}</td>
<td>{{ m.title }}</td>
<td>{{ m.genre }}</td>
<td>{{ m.country }}</td>
<td>{{ m.year }}</td>
</tr>
</tbody>
</table>
<hr/>
<span>Trouver tous les films produits par le director dont l'id est 4 ? </span>
<table class="table table-hover">
<thead class="thead-light">
<tr>
<th>Id</th>
<th>Title</th>
<th>Genre</th>
<th>Country</th>
<th>Year</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let m of movieDirector">
<td>{{ m._id }}</td>
<td>{{ m.title }}</td>
<td>{{ m.genre }}</td>
<td>{{ m.country }}</td>
<td>{{ m.year }}</td>
</tr>
</tbody>
</table>
<hr/>
<span>Trouver tous les films dont l'acteur dont l'id est 23 a joué denans ? </span>
<table class="table table-hover">
<thead class="thead-light">
<tr>
<th>Id</th>
<th>Title</th>
<th>Genre</th>
<th>Country</th>
<th>Year</th>
</tr>
</thead>
<tbody style="background: #00a8ff; color: #ffffff">
<tr>
<td>No data</td>
</tr>
</tbody>
</table>
<hr/>
<span>Tous les films dont le titre commence par "Re" ? </span>
<table class="table table-hover">
<thead class="thead-light">
<tr>
<th>Id</th>
<th>Title</th>
<th>Genre</th>
<th>Country</th>
<th>Year</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let m of movieSearch">
<td>{{ m._id }}</td>
<td>{{ m.title }}</td>
<td>{{ m.genre }}</td>
<td>{{ m.country }}</td>
<td>{{ m.year }}</td>
</tr>
</tbody>
</table>
<hr/>
<span>Tous les films produits après 200 et avent 2015 </span>
<table class="table table-hover">
<thead class="thead-light">
<tr>
<th>Id</th>
<th>Title</th>
<th>Genre</th>
<th>Country</th>
<th>Year</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let m of movieBetween">
<td>{{ m._id }}</td>
<td>{{ m.title }}</td>
<td>{{ m.genre }}</td>
<td>{{ m.country }}</td>
<td>{{ m.year }}</td>
</tr>
</tbody>
</table>
<hr/>
</div>
Add the AppRoutingModule
In Angular, the best practice is to load and configure the router in a separate, top-level module that is dedicated to routing and imported by the root AppModule.
By convention, the module class name is AppRoutingModule and it belongs in the app-routing.module.ts in the src/app folder.
app-routing-module.ts
import { QueryMoviesComponent } from './query-movies/query-movies.component';
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { FindAllMoviesComponent } from './find-all-movies/find-all-movies.component';
import { MovieDetailsComponent } from './movie-details/movie-details.component';
import { FindAllArtistesComponent } from './find-all-artistes/find-all-artistes.component';
const routes: Routes = [
{path: '', redirectTo: '/findAllArtistes', pathMatch: 'full'},
{
path: 'findAllMovies',
component: FindAllMoviesComponent
},
{
path: 'query-movies',
component: QueryMoviesComponent
},
{
path: 'movieDetails/:idMovie',
component: MovieDetailsComponent
},
{
path: 'findAllArtistes',
component: FindAllArtistesComponent
},
];
@NgModule({
imports: [RouterModule. forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
NgModules and JavaScript modules
The NgModule system is different from and unrelated to the JavaScript (ES2015) module system for managing collections of JavaScript objects. These are complementary module systems that you can use together to write your apps.
In JavaScript each file is a module and all objects defined in the file belong to that module. The module declares some objects to be public by marking them with the export key word. Other JavaScript modules use import statements to access public objects from other modules.
app-module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { NgxPaginationModule } from 'ngx-pagination';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { MovieDetailsComponent } from './movie-details/movie-details.component';
import { FindAllMoviesComponent } from './find-all-movies/find-all-movies.component';
import { QueryMoviesComponent } from './query-movies/query-movies.component';
import { HttpClientModule } from '@angular/common/http';
import { FindAllArtistesComponent } from './find-all-artistes/find-all-artistes.component';
@NgModule({
declarations: [
AppComponent,
MovieDetailsComponent,
FindAllMoviesComponent,
QueryMoviesComponent,
FindAllArtistesComponent
],
imports: [
BrowserModule,
AppRoutingModule,
HttpClientModule,
NgxPaginationModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Conclusion
Now we have an overview of Angular 10 + Spring Boot CRUD example when building a CRUD App.
We also take a look at client-server architecture for REST API using Spring Web MVC & We used Mongodb for Data, as well, we are going to continue with Angular 10 project structure for building a front-end app to make HTTP requests and consume responses.