Application Restaurant With Spring and Angular use Mongodb Part 2

Getting Started | Building an Application with Angular



 

Angular 10 Front-end

In this tutorial We going to develop an application restaurant to display all the places and we can search by name or cuisine. 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 restaurant
$ cd restaurant
$ 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'; body { font-family: Roboto, Arial, sans-serif; margin: 0; } .basic-container { padding: 30px; } .version-info { font-size: 8pt; float: right; } html, body { height: 100%; } body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }

Root Component / index.html

An Angular application is generally made up of a “root component” which will be the highest element in the Angular component hierarchy.


This component is used in the src / index.html file which is the HTML page hosting the Angular application.

src/index.html


<html lang="en"> <head> <meta charset="utf-8"> <title>App</title> <base href="/"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="icon" type="image/x-icon" href="favicon.ico"> <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyA_g9wxlUEGAkRieHzU3aqWrNme1de-trA" type="text/javascript"></script> <script src='https://kit.fontawesome.com/a076d05399.js'></script> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.3/css/bootstrap.min.css" integrity="sha384-Zug+QiDoJOrZ5t4lssLdxGhVrurbmBWopoEl+M6BdEfwnCJZtKxi1KgxUyJq13dy" crossorigin="anonymous"> <link href="https://fonts.googleapis.com/icon?family=Material+Icons&display=block" rel="stylesheet"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="icon" type="image/x-icon" href="favicon.ico"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"> <link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500" rel="stylesheet"> <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> <link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500&display=swap" rel="stylesheet"> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"></script> </head> <body> <app-root></app-root> </body> </html>

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


<!--The content below is only a placeholder and can be replaced.--> <nav class="navbar navbar-expand-sm navbar-dark" style="background: #337ab7 !important; margin-bottom: 0 !important;"> <!-- Brand/logo --> <a class="navbar-brand" routerLink="#"> <i class="fas fa-fish" style='font-size:48px;color:white; margin-top: -15px; margin-left: 10px;'></i> </a> <!-- Links --> <ul class="navbar-nav"> <li class="nav-item" style="margin-left: -5px;"> <a class="nav-link" [routerLink]="['/home-restaurant']"> Restaurants </a> </li> </ul> <span class="navbar-text" style="text-align: center !important;"> Meilleurs Restaurants à Montreuil, Seine-Saint-Denis </span> </nav> <div style="padding-bottom: 20px;"> <router-outlet></router-outlet> </div> <div class="footer" style="margin-top: 40px"> <p><i class="fas fa-apple-alt" style='font-size:24px'></i> All copy right reserve Imdrmas@gmail.com   <a href="#">Contact us 0767300918 </a> <i class="fas fa-apple-alt" style='font-size:24px'></i> </p> </div>

Model

Let's create classes by using the following command


$  ng g class Restaurant

The purpose of this class is to map the specified fields with the fields of Spring entity class.


src/app/model/Restaurant.ts


export class Restaurant { restaurant_id: number; name: string; borough: string; cuisine: string; address: any; grades: any[]; }

src/app/model/Address.ts


export class Addres { building: string; street: string; zipcode: string; coord: number[]; }

src/app/model/Grade.ts


export class Grade { grade: string[]; score: number[]; }

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/restaurant.service.ts


import {Injectable} from '@angular/core'; import {environment} from '../../environments/environment'; import {HttpClient} from '@angular/common/http'; import {Observable} from 'rxjs'; import {Restaurant} from '../model/Restaurant'; @Injectable({ providedIn: 'root' }) export class RestaurantService { private baseUrl = "http://localhost:8080"; constructor(private http: HttpClient) { } findAllRestaurants(): Observable<Restaurant[]> { return this.http.get<Restaurant[]>(`${this.baseUrl}/findAllRestaurants`); } findRestaurantById(id: string): Observable<Restaurant[]> { return this.http.get<Restaurant[]>(`${this.baseUrl}/findRestaurantById=${id}`); } findRestaurantByBorough(borough: string): Observable<Restaurant[]> { return this.http.get<Restaurant[]>(`${this.baseUrl}/findAllRestaurants/borough=${borough}`); } findRestaurantByCuisine(cuisine: string): Observable<Restaurant[]> { return this.http.get<Restaurant[]>(`${this.baseUrl}/findAllRestaurants/cuisine=${cuisine}`); } findRestaurantByBurgerKing(): Observable<Restaurant[]> { return this.http.get<Restaurant[]>(`${this.baseUrl}/findAllRestaurants/Burger-king`); } findRestaurantByNewYork(): Observable<Restaurant[]> { return this.http.get<Restaurant[]>(`${this.baseUrl}/findAllRestaurants/zipcode`); } findRestaurantByName(name: string): Observable<Restaurant[]> { return this.http.get<Restaurant[]>(`${this.baseUrl}/findAllRestaurants/name=${name}`); } findRestaurantByPizza(): Observable<Restaurant[]> { return this.http.get<Restaurant[]>(`${this.baseUrl}/findAllRestaurants/pizza`); } }

Create Angular Components

As you’ve known before, there are 9 components corresponding to 9 routes defined in AppRoutingModule.


$ ng generate component find-all-restaurants
$ ng generate component find-restaurants-borough
$ ng generate component find-restaurants-burger
$ ng generate component find-restaurants-cuisine
$ ng generate component find-restaurants-pizza
$ ng generate component home-restaurant
$ ng generate component page-restaurants
$ ng generate component restaurants-details
$ ng generate component type-cuisines

Find all restaurants component

find-all-restaurants.component.html


<div class="loader" *ngIf="spinnerLoad"></div> <div *ngIf="!spinnerLoad"> <div class="panel panel-primary"> <div class="panel-heading"><h4> <i class="fas fa-utensils"></i> All Restaurants {{total}}</h4></div> <div class="panel-body"> <div class="card hover" *ngFor="let res of restaurants | paginate:{itemsPerPage: 4, currentPage:p}"> <div class="card-img" style="background-image:url(https://images.memphistours.com/large/5f00f990272320282d98da1928fd8324.jpg);"> <div class="overlay"> <div class="overlay-content"> <a class="hover" (click)="restaurantDetails(res.restaurant_id)">More details</a> </div> </div> </div> <div class="card-content"> <h2 style="font-size: 18px; color: #1b1e24;">{{res.name}}</h2> <h2 style="font-size: 13px;"> Borough : {{res.borough}} <br> Cuisine: {{res.cuisine}}</h2> </div> </div> </div> </div> <div class="panel panel-primary"> <div class="panel-body" style="padding-bottom: 0 !important;"> <pagination-controls (pageChange)="p=$event"></pagination-controls> </div> </div> <br><br><hr> </div>

find-all-restaurants.component.scss


.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); } } * { box-sizing: border-box; } html, body { width: 100%; height: 100%; } body { padding: 1rem 0; background: #f9f9fb; } .card { width: 244px; display: inline-block; margin: 1rem; border-radius: 4px; box-shadow: 0 -1px 1px 0 rgba(0,0,0,.05), 0 1px 2px 0 rgba(0,0,0,.2); transition: all .2s ease; background: #fff; position: relative; overflow: hidden; height: 170px; &:hover, &.hover { transform: translateY(-4px); box-shadow: 0 4px 25px 0 rgba(0,0,0,.3), 0 0 1px 0 rgba(0,0,0,.25); & .card-content { box-shadow: inset 0 3px 0 0 #ccb65e; border-color: #ccb65e; } & .card-img .overlay { background-color: rgba(25,29,38,.85); transition: opacity .2s ease; opacity: 1; } } &-img { position: relative; height: 224px; width: 100%; background-color: #fff; transition: opacity .2s ease; background-position: center center; background-repeat: no-repeat; background-size: cover; & .overlay { position: absolute; left: 0; top: 0; width: 100%; height: 100%; background-color: #fff; opacity: 0; & .overlay-content { line-height: 224px; width: 100%; text-align: center; color: #fff; & a { color: #fff; padding: 0 2rem; display: inline-block; border: 1px solid rgba(255,255,255,.4); height: 40px; line-height: 40px; border-radius: 20px; cursor: pointer; text-decoration: none; &:hover, &.hover { background: #ccb65e; border-color: #ccb65e; } } } } } &-content { width: 100%; min-height: 104px; background-color: #fff; border-top: 1px solid #E9E9EB; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 1rem 2rem; transition: all .2s ease; & a { text-decoration: none; color: #202927; } & h2, a h2 { font-size: 1rem; font-weight: 500; } & p, a p { font-size: .8rem; font-weight: 400; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: rgba(32, 41, 28, .8); } } }

find-all-restaurants.component.ts


import {Component, OnInit} from '@angular/core'; import {Router} from '@angular/router'; import {Restaurant} from '../model/Restaurant'; import {RestaurantService} from '../service/restaurant.service'; @Component({ selector: 'app-find-all-restaurants', templateUrl: './find-all-restaurants.component.html', styleUrls: ['./find-all-restaurants.component.scss'] }) export class FindAllRestaurantsComponent implements OnInit { restaurants: Restaurant[]; spinnerLoad = true; total: number; grade: any; p = 0; constructor(private restaurantService: RestaurantService, private router: Router) { } ngOnInit() { this.restaurantService.findAllRestaurants().subscribe(restaurants => { this.restaurants = restaurents; this.total = this.restaurants.length; this.spinnerLoad = false; }); } restaurantDetails(id: string) { this.router.navigate(['/home-restaurant/restaurant-details', id]); } }

Find restaurants burger

find-restaurants-burger.component.html


<div class="loader" *ngIf="spinnerLoad"></div> <div *ngIf="!spinnerLoad"> <div class="panel panel-danger"> <div class="panel-heading"><h2><i class="fas fa-pizza-slice"></i> Burger Restaurants {{total}}</h2></div> <div class="panel-body"> <div class="mt-3" *ngFor="let res of restaurants | paginate:{itemsPerPage: 2, currentPage:p}"> <div class="media border p-3"> <img src="https://as2.ftcdn.net/jpg/01/05/19/29/500_F_105192919_lZE4KdODtRc6DjnFe6Ahsjg7Zup54WOf.jpg" alt="John Doe" class="mr-3 mt-3 rounded-circle" style="width:70px;"> <div class="media-body"> <h4>Name <small><i>{{res.name}}</i></small></h4> <p>City: {{res.borough}}</p> <p style="margin-top: -8px;">Cuisine: {{res.cuisine}}</p> <div class="media p-3"> <img src="https://images2.minutemediacdn.com/image/upload/c_crop,h_1126,w_2000,x_0,y_181/f_auto,q_auto,w_1100/v1554932288/shape/mentalfloss/12531-istock-637790866.jpg" alt="Jane Doe" style="width:100px; margin-top: 10px; margin-right: 10px; height: 55px;" class="img-thumbnail img-rounded"> <div class="media-body" style="margin-top: -16px;"> <h4>Address <small><i>{{res.address.street}}</i></small></h4> <p style="margin-top: -8px; text-decoration: underline;">Building: {{res.address.building}} Zipcode: {{res.address.zipcode}}</p> </div> </div> <button type="button" class="btn btn-warning" style="float: right;" (click)="restaurantDetails(res.restaurant_id)">More destails</button> </div> </div> </div> </div> </div> <div class="panel panel-danger" style="margin-top: 12px;"> <div class="panel-body" style="padding-bottom: 0 !important;"> <pagination-controls (pageChange)="p=$event"></pagination-controls> </div> </div> </div>

find-restaurants-burger.component.scss


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; /* Safari */ 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); } }

find-restaurants-burger.component.ts


import {Component, OnInit} from '@angular/core'; import {Router} from '@angular/router'; import {Restaurant} from '../model/Restaurant'; import {RestaurantService} from '../service/restaurant.service'; @Component({ selector: 'app-find-restaurants-burger', templateUrl: './find-restaurants-burger.component.html', styleUrls: ['./find-restaurants-burger.component.scss'] }) export class FindRestaurantsBurgerComponent implements OnInit { restaurants: Restaurant[]; spinnerLoad = true; total: number; showTable = false; p = 0; constructor(private restaurantService: RestaurantService, private router: Router) { } ngOnInit() { this.restaurantService.findRestaurantByBurgerKing().subscribe(restaurants => { this.restaurants = restaurents; this.total = this.restaurants.length; this.spinnerLoad = false; this.showTable = true; }); } restaurantDetails(id: string) { this.router.navigate(['/home-restaurant/restaurant-details', id]); } }

Find restaurants by cuisine

find-restaurants-cuisine.component.html


<h2> Find by cuisine </h2> <br> <form class="example" (ngSubmit)="f.form.valid && onSubmit(restaurant.cuisine)" #f="ngForm" novalidate> <input type="text" placeholder="Find by cuisine" name="cuisine" id="cuisine" required [(ngModel)]="restaurant.cuisine"> <button type="submit"><i class="fa fa-search"></i></button> </form> <br> <div *ngIf="total>0"> <div class="panel panel-success"> <div class="panel-heading"><h5> Restaurants found by cuisine </h5> <br></div> <div class="panel-body"> <div class="card" *ngFor="let res of restaurants | paginate:{itemsPerPage: 2, currentPage:p}"> <div class="card-img" style="background-image:url(https://assets.telegraphindia.com/telegraph/2020/Oct/1604164256_lead-thali.jpg);"> <div class="overlay"> <div class="overlay-content"> <a class="hover" (click)="restaurantDetails(res.cuisine)">More details</a> </div> </div> </div> <div class="card-content"> <h2 style="font-size: 18px; color: #1b1e24;">{{res.name}}</h2> <h2 style="font-size: 13px;"> Borough: {{res.borough}} <br> Cuisine: {{res.cuisine}}</h2> </div> </div> </div> </div> <div class="panel panel-success" style="margin-top: 12px;"> <div class="panel-body" style="padding-bottom: 0 !important;"> <pagination-controls (pageChange)="p=$event"></pagination-controls> </div> </div> </div> <div *ngIf="total<=0" class="alert alert-danger"> <h2>No Result found</h2> </div>

find-restaurants-cuisine.component.scss


form.example input[type=text] { padding: 10px; font-size: 17px; border: 1px solid #f2f2f2; float: left; width: 80%; background: #f1f1f1; border-radius: 5px; } form.example button { float: left; width: 20%; padding: 10px; background: #B33771; color: #ffffff; font-size: 17px; border: 1px solid #f2f2f2; border-left: none; cursor: pointer; border-radius: 5px; } form.example button:hover { background: #FD7272; } form.example::after { content: ""; clear: both; display: table; } .btn-primary { color: #D5DDE5 !important; } h2 { color: #8e9195; font-family: initial; } * { box-sizing: border-box; } html, body { width: 100%; height: 100%; } body { padding: 1rem 0; background: #f9f9fb; } .card { width: 244px; display: inline-block; margin: 1rem; border-radius: 4px; box-shadow: 0 -1px 1px 0 rgba(0,0,0,.05), 0 1px 2px 0 rgba(0,0,0,.2); transition: all .2s ease; background: #fff; position: relative; overflow: hidden; &:hover, &.hover { transform: translateY(-4px); box-shadow: 0 4px 25px 0 rgba(0,0,0,.3), 0 0 1px 0 rgba(0,0,0,.25); & .card-content { box-shadow: inset 0 3px 0 0 #ccb65e; border-color: #ccb65e; } & .card-img .overlay { background-color: rgba(25,29,38,.85); transition: opacity .2s ease; opacity: 1; } } &-img { position: relative; height: 224px; width: 100%; background-color: #fff; transition: opacity .2s ease; background-position: center center; background-repeat: no-repeat; background-size: cover; & .overlay { position: absolute; left: 0; top: 0; width: 100%; height: 100%; background-color: #fff; opacity: 0; & .overlay-content { line-height: 224px; width: 100%; text-align: center; color: #fff; & a { color: #fff; padding: 0 2rem; display: inline-block; border: 1px solid rgba(255,255,255,.4); height: 40px; line-height: 40px; border-radius: 20px; cursor: pointer; text-decoration: none; &:hover, &.hover { background: #ccb65e; border-color: #ccb65e; } } } } } &-content { width: 100%; min-height: 104px; background-color: #fff; border-top: 1px solid #E9E9EB; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 1rem 2rem; transition: all .2s ease; & a { text-decoration: none; color: #202927; } & h2, a h2 { font-size: 1rem; font-weight: 500; } & p, a p { font-size: .8rem; font-weight: 400; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: rgba(32, 41, 28, .8); } } }

find-restaurants-cuisine.component.ts


import {Component, OnInit} from '@angular/core'; import {Router} from '@angular/router'; import {Restaurant} from '../model/Restaurant'; import {RestaurantService} from '../service/restaurant.service'; @Component({ selector: 'app-find-restaurants-cuisine', templateUrl: './find-restaurants-cuisine.component.html', styleUrls: ['./find-restaurants-cuisine.component.scss'] }) export class FindRestaurantsCuisineComponent implements OnInit { restaurants: Restaurant[]; spinnerLoad = true; total: number; p = 0; constructor(private restaurantService: RestaurantService, private router: Router) { } ngOnInit(cuisine: string) { this.restaurantService.findRestaurantByCuisine(cuisine).subscribe(restaurants => { this.restaurants = restaurents; this.total = this.restaurants.length; this.spinnerLoad = false; }); } restaurantDetails(id: string) { this.router.navigate(['/home-restaurant/restaurant-details', id]); } }

Find restaurants borough component

find-restaurants-borough.component.html


<div class="loader" *ngIf="spinnerLoad"></div> <div *ngIf="!spinnerLoad"> <div class="panel panel-danger"> <div class="panel-heading"><h2><i class="fas fa-pizza-slice"></i> Pizza Restaurants {{total}}</h2></div> <div class="panel-body"> <div class="mt-3" *ngFor="let res of restaurants | paginate:{itemsPerPage: 2, currentPage:p}"> <div class="media border p-3"> <img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcS-NWPfqxwQpB46y4OHooy1FHxiWCJFu2dU4vMzUq04ofBkFEl6&s" alt="John Doe" class="mr-3 mt-3 rounded-circle" style="width:70px;"> <div class="media-body"> <h4>Name <small><i>{{res.name}}</i></small></h4> <p>City: {{res.borough}}</p> <p style="margin-top: -8px;">Cuisine: {{res.cuisine}}</p> <div class="media p-3"> <img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcR5laPR78NDgWsF2zds7iK-PVY_Abr_O3mBAUCw7k-R5ahz5DxF&s" alt="Jane Doe" style="width:100px; margin-top: 10px; margin-right: 10px; height: 55px;" class="img-thumbnail img-rounded"> <div class="media-body" style="margin-top: -16px;"> <h4>Address <small><i>{{res.address.street}}</i></small></h4> <p style="margin-top: -8px; text-decoration: underline;">Building: {{res.address.building}} Zipcode: {{res.address.zipcode}}</p> </div> </div> <button type="button" class="btn btn-warning" style="float: right;" (click)="restaurantDetails(res.restaurant_id)">More destails</button> </div> </div> </div> </div> </div> <div class="panel panel-danger" style="margin-top: 12px;"> <div class="panel-body" style="padding-bottom: 0 !important;"> <pagination-controls (pageChange)="p=$event"></pagination-controls> </div> </div> </div>

find-restaurants-borough.component.scss


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; /* Safari */ 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); } }

Find restaurants borough component

find-restaurants-borough.component.ts


import {Component, OnInit} from '@angular/core'; import {Router} from '@angular/router'; import {Restaurant} from '../model/Restaurant'; import {RestaurantService} from '../service/restaurant.service'; @Component({ selector: 'app-find-restaurants-borough', templateUrl: './find-restaurants-borough.component.html', styleUrls: ['./find-restaurants-borough.component.scss'] }) export class FindRestaurantsBoroughComponent implements OnInit { restaurants: Restaurant[]; spinnerLoad = true; total: number; grade: any; p = 0; constructor(private restaurantService: RestaurantService, private router: Router) { } ngOnInit(name: string) { this.restaurantService.findRestaurantByBorough(name).subscribe(restaurants => { this.restaurants = restaurents; this.total = this.restaurants.length; this.spinnerLoad = false; }); } restaurantDetails(id: string) { this.router.navigate(['/home-restaurant/restaurant-details', id]); } }

Home restaurant component

home-restaurant.component.html


<br><br> <div class="container"> <div class="row"> <div class="col-lg-3"> <br> <ul class="list-group"> <li class="list-group-item" style="background: #337ab7 !important; color: #FFF; font-size: 22px; font-family: initial;"><i class='fab fa-searchengin'></i> Find restaurant: </li> <li class="list-group-item"> <a [routerLink]="['/home-restaurant/find-all-restaurant']" routerLinkActive="router-link-active"><i class='fas fa-map-pin'></i> Find All Restaurants </a> </li> <li class="list-group-item"> <a [routerLink]="['/home-restaurant/findByPizza']" routerLinkActive="router-link-active"><i class='fas fa-map-pin'></i> Find Restaurant Pizza </a> </li> <li class="list-group-item"> <a [routerLink]="['/home-restaurant/findByBurgerKing']" routerLinkActive="router-link-active"><i class='fas fa-map-pin'></i> Find by burgerking </a> </li> <li class="list-group-item"> <a [routerLink]="['/home-restaurant/findRestaurantBorough']" routerLinkActive="router-link-active"><i class='fas fa-map-pin'></i> Find by borough </a> </li> <li class="list-group-item"> <a [routerLink]="['/home-restaurant/findRestaurantCuisine']" routerLinkActive="router-link-active"><i class='fas fa-map-pin'></i> Find by cuisine </a> </li> </ul> </div> <div class="col-lg-9"> <div class="topnav"> <a class="active" routerLink="/home-restaurant"><i class="fas fa-home"></i> Home</a> <a routerLink="/home-restaurant">About</a> <a routerLink="/home-restaurant">Contact</a> <div class="login-container"> <form class="example" (ngSubmit)="f.form.valid && onSubmit(restaurant.name)" #f="ngForm" novalidate> <label for="name"></label><input type="text" placeholder="Find by name" name="name" id="name" required [(ngModel)]="restaurant.name"> <button type="submit"><i class="fa fa-search"></i></button> </form> </div> </div> <br> <div *ngIf="total>0" id="search"> <div class="panel panel-success"> <div class="panel-heading"><h5> Restaurants found by cuisine </h5> <br></div> <div class="panel-body"> <div class="card" *ngFor="let res of restaurants"> <div class="card-img" style="background-image:url(https://assets.telegraphindia.com/telegraph/2020/Oct/1604164256_lead-thali.jpg);"> <div class="overlay"> <div class="overlay-content"> <a class="hover" (click)="restaurantDetails(res.restaurant_id)">More details</a> </div> </div> </div> <div class="card-content"> <h2 style="font-size: 18px; color: #1b1e24;">{{res.name}}</h2> <h2 style="font-size: 13px;"> Borough : {{res.borough}} <br> Cuisine: {{res.cuisine}}</h2> </div> </div> </div> </div> </div> <div *ngIf="total<=0" class="alert alert-danger"> <h2>No Result found</h2> </div> <router-outlet></router-outlet> </div> </div> </div>

home-restaurant.component.scss


.carousel-item img { width: 100%; height: 600px; } #map { height: 500px; width: 100%; } * { box-sizing: border-box; } body { margin: 0; font-family: Arial, Helvetica, sans-serif; } .topnav { overflow: hidden; background-color: #e9e9e9; border-radius: 5px; } .topnav a { float: left; display: block; color: black; text-align: center; padding: 14px 16px; text-decoration: none; font-size: 17px; } .topnav a:hover { background-color: #ddd; color: black; } .topnav a.active { background-color: #e67e22; color: white; } .topnav .login-container { float: right; margin-top: -5px; } .topnav input[type=text] { padding: 6px; margin-top: 8px; font-size: 17px; border: none; width: 120px; } .topnav .login-container button { float: right; padding: 9px 10px; margin-top: -44px; margin-right: 16px; background-color: #555; color: white; font-size: 17px; border: none; cursor: pointer; } .topnav .login-container button:hover { background-color: #0984e3; } @media screen and (max-width: 600px) { .topnav .login-container { float: none; } .topnav a, .topnav input[type=text], .topnav .login-container button { float: none; display: block; text-align: left; width: 100%; margin: 0; padding: 14px; } .topnav input[type=text] { border: 1px solid #ccc; } } * {box-sizing: border-box;} .cuisine { position: relative; } .cuisine .image-cuisine { display: block; width: 100%; height: 140px; border: 1px solid #ddd; border-radius: 4px; padding: 10px; } .overlay { position: absolute; bottom: 10px; background: rgb(0, 0, 0); background: rgba(0, 0, 0, 0.5); width: 80%; transition: .5s ease; opacity:0; color: white; font-size: 20px; padding: 20px; text-align: center; margin-left: 10px; cursor: pointer; } .cuisine .overlay { opacity: 1; } .title { color: #00a8ff; text-decoration: underline; } .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); } } .checked { color: orange; } #pagination { background: #D5DDE5; width: 96%; margin-left: 18px; margin-top: 10px; padding-top: 7px; border-radius: 5px; } .btn-read-more { border: 2px solid black; background-color: white; color: black; padding: 10px 28px; font-size: 16px; cursor: pointer; margin-top: 10px; float: right; margin-right: 15px; } .info-read-more { border-color: #2196F3; color: dodgerblue; } .info-read-more:hover { background: #2196F3; color: white; } .newYorkRestaurant { position: relative; font-family: Arial; } .newYorkRestaurant .text-block { position: absolute; bottom: 0; background-color: #00000082; color: white; width: 100%; padding-left: 4px; } .text-block { cursor: pointer; } form.example input[type=text] { padding: 10px; font-size: 17px; border: 1px solid #f2f2f2; float: left; width: 80%; background: #f1f1f1; border-radius: 5px; } form.example button { float: left; width: 20%; padding: 10px; background: #B33771; color: #ffffff; font-size: 17px; border: 1px solid #f2f2f2; border-left: none; cursor: pointer; border-radius: 5px; } form.example button:hover { background: #FD7272; } form.example::after { content: ""; clear: both; display: table; } .btn-primary { color: #D5DDE5 !important; } h2 { color: #8e9195; font-family: initial; } * { box-sizing: border-box; } html, body { width: 100%; height: 100%; } body { padding: 1rem 0; background: #f9f9fb; } .card { width: 244px; display: inline-block; margin: 1rem; border-radius: 4px; box-shadow: 0 -1px 1px 0 rgba(0,0,0,.05), 0 1px 2px 0 rgba(0,0,0,.2); transition: all .2s ease; background: #fff; position: relative; overflow: hidden; &:hover, &.hover { transform: translateY(-4px); box-shadow: 0 4px 25px 0 rgba(0,0,0,.3), 0 0 1px 0 rgba(0,0,0,.25); & .card-content { box-shadow: inset 0 3px 0 0 #ccb65e; border-color: #ccb65e; } & .card-img .overlay { background-color: rgba(25,29,38,.85); transition: opacity .2s ease; opacity: 1; } } &-img { position: relative; height: 224px; width: 100%; background-color: #fff; transition: opacity .2s ease; background-position: center center; background-repeat: no-repeat; background-size: cover; & .overlay { position: absolute; left: 0; top: 0; width: 100%; height: 100%; background-color: #fff; opacity: 0; & .overlay-content { line-height: 224px; width: 100%; text-align: center; color: #fff; & a { color: #fff; padding: 0 2rem; display: inline-block; border: 1px solid rgba(255,255,255,.4); height: 40px; line-height: 40px; border-radius: 20px; cursor: pointer; text-decoration: none; &:hover, &.hover { background: #ccb65e; border-color: #ccb65e; } } } } } &-content { width: 100%; min-height: 104px; background-color: #fff; border-top: 1px solid #E9E9EB; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 1rem 2rem; transition: all .2s ease; & a { text-decoration: none; color: #202927; } & h2, a h2 { font-size: 1rem; font-weight: 500; } & p, a p { font-size: .8rem; font-weight: 400; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: rgba(32, 41, 28, .8); } } }

home-restaurant.component.ts


import {Component, OnInit} from '@angular/core'; import {Router} from '@angular/router'; import {Restaurant} from '../model/Restaurant'; import {RestaurantService} from '../service/restaurant.service'; @Component({ selector: 'app-find-restaurants-burger', templateUrl: './find-restaurants-burger.component.html', styleUrls: ['./find-restaurants-burger.component.scss'] }) export class HomeRestaurantComponent implements OnInit { restaurants: Restaurant[]; spinnerLoad = true; total: number; submitted = false; constructor(private restaurantService: RestaurantService, private router: Router) { } ngOnInit() { this.restaurantService.findAllRestaurants().subscribe(restaurants => { this.restaurants = restaurants; }); } onSubmit(name: string) { this.restaurantService.findRestaurantByName(name).subscribe(restaurants => { this.restaurants = restaurants.slice(0, 3); this.total = this.restaurants.length; this.submitted = true; }); } restaurantDetails(id: string) { this.router.navigate(['/home-restaurant/restaurant-details', id]); } }

Page restaurants component

page-restaurants.component.html


<div class="loader" *ngIf="spinnerLoad"></div> <div *ngIf="!spinnerLoad"> <div class="row"> <div class="panel panel-primary"> <div class="panel-heading"> <p class="title" style="color: #FFFFFF"> <i class="fas fa-pepper-hot"></i> Parcourir Montreuil par type de cuisine </p></div> <div class="panel-body"> <div class="cuisine"> <div class="col-md-3" *ngFor="let cuisine of filteredData"> <img src="https://i.ibb.co/6HKRRxn/salade.jpg" alt="img" class="image-cuisine"> <div class="overlay" (click)="restaurantTypeCuisine(cuisine.cuisine)">{{cuisine.cuisine}}</div> </div> </div> <button class="btn-read-more info-read-more" *ngIf="showAllCuisine">Read more</button> <button class="btn-read-more info-read-more" *ngIf="hideCuisine">Read more</button> </div> </div> </div> <div class="row"> <div class="panel panel-warning"> <div class="panel-heading"> <p class="title"><i class="fas fa-pizza-slice"></i> Best restaurants </p> </div> <div class="panel-body" style="display: flex;"> <div class="col-md-3" *ngFor="let res of restaurantsReserve"> <div class="card" style="width: 18rem;"> <img src="https://media.gettyimages.com/photos/different-types-of-food-on-rustic-wooden-table-picture-id861188910?s=612x612" class="card-img-top" alt="..."> <div class="card-body"> <h5 class="card-title" style="font-size: 13px;">{{res.name}}</h5> <p class="card-text">{{res.borough}}, {{res.cuisine}}</p> <button (click)="restaurantDetails(res.restaurant_id)" class="btn btn-warning">Trouver une table</button> </div> </div> </div> </div> </div> </div> <br><br><div class="row"> <div class="panel panel-danger"> <div class="panel-heading"> <p class="title"><i class="fas fa-hamburger"></i> Offres Spéciales Burger King </p></div> <div class="panel-body"> <div class="card" *ngFor="let burger of restaurantsBurgerKings | paginate:{itemsPerPage: 1, currentPage:p}" style="margin-bottom: 15px;"> <h5 class="card-header" style="margin-top: 0;">{{burger.name}}</h5> <div class="card-body" style="display: flex;"> <div class="col-md-4"> <img src="https://www.toute-la-franchise.com/images/zoom/burger-kink.jpg" alt="img" class="img-thumbnail"> <h5 class="card-title">Address: {{burger.borough}}</h5> <p class="card-text"> Rue {{burger.address.street}}, {{burger.address.zipcode}}, {{burger.address.building}}</p> <h6>Rating</h6> <span class="fa fa-star"></span> <span class="fa fa-star"></span> <span class="fa fa-star"></span> <span class="fa fa-star"></span> <span><i class="fas fa-star-half-alt"></i></span><br> </div> <div class="col-md-5"> <ul class="list-group"> <li class="list-group-item disabled" aria-disabled="true">Score and Grades </li> <li class="list-group-item" *ngFor="let g of burger.grades"> Score > {{g.score}} Grade > {{g.grade}} </li> </ul> </div> <div class="col-md-3" style="margin: auto 50px;"> <button (click)="restaurantDetails(burger.restaurant_id)" class="btn btn-danger btn-lg">Réserver</button> </div> </div> </div> </div> </div> <div class="panel panel-danger" style="margin-top: 12px;"> <div class="panel-body" style="padding-bottom: 0 !important;"> <pagination-controls (pageChange)="p=$event"></pagination-controls> </div> </div> </div> <div class="row"> <div class="panel panel-info"> <div class="panel-heading"><p class="title"><i class="fas fa-hamburger"></i> New York Restaurants </p></div> <div class="panel-body" style="display: flex;"> <div class="col-md-3" *ngFor="let newYork of restaurantsNewYork"> <div class="newYorkRestaurant"> <img src="https://media-cdn.tripadvisor.com/media/photo-s/0d/61/34/d5/new-york-restaurant.jpg" alt="Nature" style="width:100%;" class="img-thumbnail"> <div class="text-block"> <h4>{{newYork.address.zipcode}}</h4> <p (click)="restaurantDetails(newYork.restaurant_id)" style="font-size: 12px;">{{newYork.name}} <i class="fas fa-eye-slash"></i> </p> </div> </div> </div> </div> </div> </div> <br><hr> </div>

page-restaurants.component.scss


* {box-sizing: border-box;} body { margin: 0; font-family: Arial, Helvetica, sans-serif; } .topnav { overflow: hidden; background-color: #e9e9e9; } .topnav a { float: left; display: block; color: black; text-align: center; padding: 14px 16px; text-decoration: none; font-size: 17px; } .topnav a:hover { background-color: #ddd; color: black; } .topnav a.active { background-color: #2196F3; color: white; } .topnav .login-container { float: right; } .topnav input[type=text] { padding: 6px; margin-top: 8px; font-size: 17px; border: none; width: 120px; } .topnav .login-container button { float: right; padding: 6px 10px; margin-top: 8px; margin-right: 16px; background-color: #555; color: white; font-size: 17px; border: none; cursor: pointer; } .topnav .login-container button:hover { background-color: green; } @media screen and (max-width: 600px) { .topnav .login-container { float: none; } .topnav a, .topnav input[type=text], .topnav .login-container button { float: none; display: block; text-align: left; width: 100%; margin: 0; padding: 14px; } .topnav input[type=text] { border: 1px solid #ccc; } } * {box-sizing: border-box;} .cuisine { position: relative; display: flex; } .cuisine .image-cuisine { display: block; width: 100%; height: 140px; border: 1px solid #ddd; border-radius: 4px; padding: 10px; } .overlay { position: absolute; bottom: 10px; background: rgb(0, 0, 0); background: rgba(0, 0, 0, 0.5); /* Black see-through */ width: 76%; transition: .5s ease; opacity:0; color: white; font-size: 20px; padding: 20px; text-align: center; margin-left: 10px; cursor: pointer; } .cuisine .overlay { opacity: 1; } .title { color: #00a8ff; text-decoration: underline; } .loader { border: 16px solid #f3f3f3; border-radius: 50%; border-top: 16px solid #007bff !important; width: 100px; height: 100px; -webkit-animation: spin 2s linear infinite; /* Safari */ 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); } } .checked { color: orange; } #pagination { background: #D5DDE5; width: 96%; margin-left: 18px; margin-top: 10px; padding-top: 7px; border-radius: 5px; } .btn-read-more { border: 2px solid black; background-color: white; color: black; padding: 10px 28px; font-size: 16px; cursor: pointer; margin-top: 10px; float: right; margin-right: 15px; } .info-read-more { border-color: #2196F3; color: dodgerblue; } .info-read-more:hover { background: #2196F3; color: white; } .newYorkRestaurant { position: relative; font-family: Arial; } .newYorkRestaurant .text-block { position: absolute; bottom: 0; background-color: #00000082; color: white; width: 100%; padding-left: 4px; } .text-block { cursor: pointer; } #search .card { width: 244px; display: inline-block; margin: 1rem; border-radius: 4px; box-shadow: 0 -1px 1px 0 rgba(0,0,0,.05), 0 1px 2px 0 rgba(0,0,0,.2); transition: all .2s ease; background: #fff; position: relative; overflow: hidden; &:hover, &.hover { transform: translateY(-4px); box-shadow: 0 4px 25px 0 rgba(0,0,0,.3), 0 0 1px 0 rgba(0,0,0,.25); & .card-content { box-shadow: inset 0 3px 0 0 #ccb65e; border-color: #ccb65e; } & .card-img .overlay { background-color: rgba(25,29,38,.85); transition: opacity .2s ease; opacity: 1; } } &-img { position: relative; height: 224px; width: 100%; background-color: #fff; transition: opacity .2s ease; background-position: center center; background-repeat: no-repeat; background-size: cover; & .overlay { position: absolute; left: 0; top: 0; width: 100%; height: 100%; background-color: #fff; opacity: 0; & .overlay-content { line-height: 224px; width: 100%; text-align: center; color: #fff; & a { color: #fff; padding: 0 2rem; display: inline-block; border: 1px solid rgba(255,255,255,.4); height: 40px; line-height: 40px; border-radius: 20px; cursor: pointer; text-decoration: none; &:hover, &.hover { background: #ccb65e; border-color: #ccb65e; } } } } } &-content { width: 100%; min-height: 104px; background-color: #fff; border-top: 1px solid #E9E9EB; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 1rem 2rem; transition: all .2s ease; & a { text-decoration: none; color: #202927; } & h2, a h2 { font-size: 1rem; font-weight: 500; } & p, a p { font-size: .8rem; font-weight: 400; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: rgba(32, 41, 28, .8); } } }

page-restaurants.component.ts


import { Component, OnInit } from '@angular/core'; import { Router} from '@angular/router'; import { Restaurant } from '../model/Restaurant'; import { RestaurantService } from '../service/restaurant.service'; @Component({ selector: 'app-page-restaurants', templateUrl: './page-restaurants.component.html', styleUrls: ['./page-restaurants.component.scss'] }) export class PageRestaurantsComponent implements OnInit { restaurantsReserve: Restaurant[]; cuisines: Restaurant[]; restaurantsBurgerKings: Restaurant[]; filteredData: Restaurant[]; restaurantsNewYork: Restaurant[]; restaurant: any = {}; address: any = {}; showAllCuisine = true; hideCuisine = false; spinnerLoad = true; p = 0; constructor(private restaurantService: RestaurantService, private router: Router) { } ngOnInit() { this.findNewYork(); this.findBurgerKing(); this.findAllRestaurants(); this.findRestaurantsReserve(); } findRestaurantsReserve() { this.restaurantService.findAllRestaurants().subscribe(restaurants => { this.restaurantsReserve = restaurants.slice(0, 3); this.spinnerLoad = false; }); } findAllRestaurants() { this.restaurantService.findAllRestaurants().subscribe(restaurants => { this.cuisines = restaurants.slice(0, 4); this.filteredData = Array.from(this.cuisines.reduce((m, t) => m.set(t.cuisine, t), new Map()).values()); this.spinnerLoad = false; }); } restaurantDetails(id: string) { this.router.navigate(['/home-restaurant/restaurant-details', id]); } restaurantTypeCuisine(cuisine: string) { this.router.navigate(['/home-restaurant/type-cuisine', cuisine]); } findBurgerKing() { this.restaurantService.findRestaurantByBurgerKing().subscribe(restaurants => { this.restaurantsBurgerKings = restaurants; }); } findNewYork() { this.restaurantService.findRestaurantByNewYork().subscribe(newYork => { this.restaurantsNewYork = newYork.slice(0, 4); }); } readMoreNewYork() { this.restaurantService.findRestaurantByNewYork().subscribe(newYork => { this.restaurantsNewYork = newYork; }); } }

Restaurants details component

restaurants-details.component.html


<div class="jumbotron"> <h1 class="display-4"> <i class="fas fa-utensils"></i> Restaurant details</h1> <hr> <br> <div class="row"> <div class="col-md-8"> <span> <i class="fas fa-home"></i> Name: {{restaurant.name}} <br> <i class="fab fa-accusoft"></i> Cuisine: {{restaurant.cuisine}} <br> <i class="fas fa-city"></i> Borough: {{restaurant.borough}} </span> <hr> <table class="table table-hover"> <thead class="thead-light"> <tr> <th>Grade</th> <th>Score</th> </tr> </thead> <tbody> <tr *ngFor="let s of restaurant.grades"> <td>{{s.grade}}</td> <td>{{s.score}}</td> </tr> </tbody> </table> </div> <div class="col-sm-4"> <div class="card text-dark bg-light"> <div class="card-header bg-dark text-center text-light"><h4> Informtation </h4></div> <div class="card-body"> <div class="list-group"> <span>Address: {{restaurant.address.street}}</span> <span>Building: {{restaurant.address.building}} </span> <span>Zip code: {{restaurant.address.zipcode}}</span> </div> </div> <div class="card-footer bg-secondary border-danger text-right"> <a routerLink="/home-restaurant" class="btn btn-info btn-md">home</a> </div> </div> </div> </div> <br> <hr style="margin-top: 0px; border: 1px solid #F48989;"> </div>

restaurants-details.component.scss


.sebm-google-map-container { height: 300px; } .jumbotron { font-family: initial; }

restaurants-details.component.ts


import {Component, forwardRef, Inject, NgZone, OnInit, ViewChild} from '@angular/core'; import {ActivatedRoute} from '@angular/router'; import { Address } from '../model/Address'; import { Restaurant } from '../model/Restaurant'; import { RestaurantService } from '../service/restaurant.service'; @Component({ selector: 'app-restaurants-details', templateUrl: './restaurants-details.component.html', styleUrls: ['./restaurants-details.component.scss'] }) export class RestaurantsDetailsComponent implements OnInit { restaurants: Restaurant[]; restaurant: Restaurant = new Restaurant(); address: Address = new Address(); idRestaurant: string; constructor(private restaurantService: RestaurantService, private route: ActivatedRoute) { } ngOnInit() { this.idRestaurant = this.route.snapshot.params.idRestaurant; this.restaurantService.findRestaurantById(this.idRestaurant).subscribe(restaurants => { this.restaurants = restaurants; this.restaurants.forEach(restaurant => { this.restaurant = restaurant; this.address = this.restaurant.address; }); }); } }

Type cuisines component

type-cuisines.component.html


<div class="loader" *ngIf="spinnerLoad"></div> <div *ngIf="!spinnerLoad"> <div class="panel panel-danger"> <div class="panel-heading"><h2><i class="fas fa-pizza-slice"></i> Type de cuisine trouver {{total}}</h2></div> <div class="panel-body"> <div class="mt-3" *ngFor="let res of restaurants | paginate:{itemsPerPage: 12, currentPage:p}"> <div class="media border p-3"> <img src="https://www.tasteatlas.com/Images/Dishes/357efb62768748a8898836bcf186222c.jpg" alt="John Doe" class="mr-3 mt-3 rounded-circle" style="width:70px;"> <div class="media-body"> <h4>Name <small><i>{{res.name}}</i></small></h4> <p>City: {{res.borough}}</p> <p style="margin-top: -8px;">Cuisine: {{res.cuisine}}</p> <div class="media p-3"> <img src="https://amayei.nyc3.digitaloceanspaces.com/2019/04/830559308a3c9a864e02daee8b66177818e1ef77.jpg" alt="Jane Doe" style="width:100px; margin-top: 10px; margin-right: 10px; height: 55px;" class="img-thumbnail img-rounded"> <div class="media-body" style="margin-top: -16px;"> <h4>Address <small><i>{{res.address.street}}</i></small></h4> <p>Coordonner: {{res.address.coord}}</p> <p style="margin-top: -8px; text-decoration: underline;">Building: {{res.address.building}} Zipcode: {{res.address.zipcode}}</p> </div> </div> <button type="button" class="btn btn-warning" style="float: right;" (click)=" restaurantDetails(res.restaurant_id)">More destails</button> </div> </div> </div> </div> </div> <div class="panel panel-danger" style="margin-top: 12px;"> <div class="panel-body" style="padding-bottom: 0 !important;"> <pagination-controls (pageChange)="p=$event"></pagination-controls> </div> </div> </div>

type-cuisines.component.scss


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; /* Safari */ 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); } }

type-cuisines.component.ts


import {Component, OnInit} from '@angular/core'; import {Restaurant} from '../model/Restaurant'; import {ActivatedRoute, Router} from '@angular/router'; import {RestaurantService} from '../service/restaurant.service'; @Component({ selector: 'app-type-cuisines', templateUrl: './type-cuisines.component.html', styleUrls: ['./type-cuisines.component.scss'] }) export class TypeCuisinesComponent implements OnInit { typeCuisine: string; restaurants: Restaurant[]; spinnerLoad = true; total: number; p = 0; constructor(private restaurantService: RestaurantService, private route: ActivatedRoute, private router: Router) { } ngOnInit() { this.typeCuisine = this.route.snapshot.params.typeCuisine; this.restaurantService.findRestaurantByCuisine(this.typeCuisine).subscribe(restaurants => { this.restaurants = restaurants; this.total = this.restaurants.length; this.spinnerLoad = false; }); } restaurantDetails(id: string) { this.router.navigate(['/home-restaurant/restaurant-details', id]); } }

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 { FindRestaurantsPizzaComponent} from './find-restaurants-pizza/find-restaurants-pizza.component'; import { HomeRestaurantComponent} from './home-restaurant/home-restaurant.component'; import { NgModule} from '@angular/core'; import { Routes, RouterModule} from '@angular/router'; import { FindAllRestaurantsComponent} from './find-all-restaurants/find-all-restaurants.component'; import { FindRestaurantsBoroughComponent} from './find-restaurants-borough/find-restaurants-borough.component'; import { FindRestaurantsBurgerComponent} from './find-restaurants-burger/find-restaurants-burger.component'; import { FindRestaurantsCuisineComponent} from './find-restaurants-cuisine/find-restaurants-cuisine.component'; import { PageRestaurantsComponent} from './page-restaurants/page-restaurants.component'; import { RestaurantsDetailsComponent} from './restaurants-details/restaurants-details.component'; import { TypeCuisinesComponent} from './type-cuisines/type-cuisines.component'; const routes: Routes = [ { path: '', redirectTo: 'home-restaurant', pathMatch: 'full'}, { path: 'home-restaurant', component: HomeRestaurantComponent, children: [ { path: 'find-all-restaurant', component: FindAllRestaurantsComponent, }, { path: 'findRestaurantBorough', component: FindRestaurantsBoroughComponent }, { path: 'findByPizza', component: FindRestaurantsPizzaComponent }, { path: 'findRestaurantCuisine', component: FindRestaurantsCuisineComponent }, { path: '', component: PageRestaurantsComponent }, { path: 'restaurant-details/:idRestaurant', component: RestaurantsDetailsComponent, }, { path: 'type-cuisine/:typeCuisine', component: TypeCuisinesComponent }, { path: 'findByBurgerKing', component: FindRestaurantsBurgerComponent }, ] }, ]; @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 { AppRoutingModule} from './app-routing.module'; import { AppComponent} from './app.component'; import { FormsModule, ReactiveFormsModule} from '@angular/forms'; import { NgxPaginationModule} from 'ngx-pagination'; import { FindAllRestaurantsComponent } from './find-all-restaurants/find-all-restaurants.component'; import { HomeRestaurantComponent } from './home-restaurant/home-restaurant.component'; import { HttpClientModule } from '@angular/common/http'; import { FindRestaurantsBoroughComponent } from './find-restaurants-borough/find-restaurants-borough.component'; import { FindRestaurantsBurgerComponent } from './find-restaurants-burger/find-restaurants-burger.component'; import { FindRestaurantsCuisineComponent } from './find-restaurants-cuisine/find-restaurants-cuisine.component'; import { PageRestaurantsComponent } from './page-restaurants/page-restaurants.component'; import { RestaurantsDetailsComponent } from './restaurants-details/restaurants-details.component'; import { TypeCuisinesComponent } from './type-cuisines/type-cuisines.component'; import { FindRestaurantsPizzaComponent } from './find-restaurants-pizza/find-restaurants-pizza.component'; @NgModule({ declarations: [ AppComponent, FindAllRestaurantsComponent, HomeRestaurantComponent, FindRestaurantsBoroughComponent, FindRestaurantsBurgerComponent, FindRestaurantsCuisineComponent, PageRestaurantsComponent, RestaurantsDetailsComponent, TypeCuisinesComponent, FindRestaurantsPizzaComponent ], imports: [ BrowserModule, AppRoutingModule, ReactiveFormsModule, NgxPaginationModule, HttpClientModule, FormsModule ], 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.




Post a Comment

Previous Post Next Post


Follow us on facebook