In this tutorial, we show you Angular 6 Http Client & Node.js/Express Server example that uses Sequelize ORM to do CRUD with MariaDB and Angular 6 as a front-end technology to make request and receive response.
Related posts:
– Mongoose CRUD MongoDB – Angular 6 HttpClient Get/Post/Put/Delete – Node.js/Express RestAPIs
– Angular 6 HttpClient – Upload Files/Download Files to MySQL with Node.js/Express RestAPIs – using Multer + Sequelize ORM
– Angular 6 HttpClient – PostgreSQL – Node.js/Express Sequelize CRUD APIs – Post/Get/Put/Delete
Related Pages:
I. Technologies
– Java 1.8
– Maven 3.3.9
– Node.js/Express
– Sequelize ORM
– Angular 6
– RxJS 6
– MariaDB
II. Overview
1. Node.js Server
2. Angular 6 Client
III. Practice
1. Project Structure
1.1 Node.js Server
– customer.model.js
file corresponds to entity and table customer.
– customer.controller.js
is used to interact with MariaDB via CRUD APIs of Sequelize ORM.
– customer.route.js
is used to configure Express RestAPIs.
– Configuration for MariaDB Datasource and Sequelize ORM properties in env.js
and db.config.js
1.2 Angular 6 Client
In this example, we focus on:
– 4 components: customers-list, customer-details, create-customer, search-customer.
– 3 modules: FormsModule, HttpClientModule, AppRoutingModule.
– customer.ts: class Customer (id, firstName, lastName)
– customer.service.ts: Service for Http Client methods
2. How to do
2.1 Node.js Server
2.1.1 Setup NodeJs/Express Project
Following the guide to create a NodeJS/Express project.
Install Sequelize & MariaDB:
$npm install sequelize mysql2 cors--save
-> package.json
file:
{ "name": "nodejs-express-sequelizejs-mariadb", "version": "1.0.0", "description": "nodejs-express-sequelizejs-mariadb", "main": "server.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [ "Node.js-Express-SequelizeJS-MariaDB" ], "author": "Grokonez.com", "license": "ISC", "dependencies": { "cors": "^2.8.4", "express": "^4.16.3", "mysql2": "^1.5.3", "sequelize": "^4.37.6" } }
2.1.2 Setup Sequelize MariaDB Connection
– Create ./app/config/env.js
file:
const env = { database: 'gkzdb', username: 'root', password: '12345', host: 'localhost', dialect: 'mysql', pool: { max: 5, min: 0, acquire: 30000, idle: 10000 } }; module.exports = env;
– Setup Sequelize-MariaDB connection in ./app/config/db.config.js
file:
const env = require('./env.js'); const Sequelize = require('sequelize'); const sequelize = new Sequelize(env.database, env.username, env.password, { host: env.host, dialect: env.dialect, operatorsAliases: false, pool: { max: env.max, min: env.pool.min, acquire: env.pool.acquire, idle: env.pool.idle } }); const db = {}; db.Sequelize = Sequelize; db.sequelize = sequelize; //Models/tables db.customers = require('../model/customer.model.js')(sequelize, Sequelize); module.exports = db;
2.1.3 Sequelize Model
module.exports = (sequelize, Sequelize) => { const Customer = sequelize.define('customer', { name: { type: Sequelize.STRING }, age: { type: Sequelize.INTEGER }, active: { type: Sequelize.BOOLEAN, defaultValue: false } }); return Customer; }
2.1.4 Express RestAPIs
Route
-> Define Customer’s routes in ./app/controller/customer.route.js
file:
module.exports = function(app) { const customers = require('../controller/customer.controller.js'); // Create a new Customer app.post('/api/customers/create', customers.create); // Retrieve all Customer app.get('/api/customers', customers.findAll); // Retrieve a single Customer by Id app.get('/api/customers/:customerId', customers.findById); app.get('/api/customers/age/:age', customers.lookUpByAge); // Update a Customer with Id app.put('/api/customers/:customerId', customers.update); // Delete a Customer with Id app.delete('/api/customers/:customerId', customers.delete); // Delete all Customers app.delete('/api/customers/all/delete', customers.deleteAll); }
Controller
-> Implement Customer’s controller in ./app/controller/customer.controller.js
file:
const db = require('../config/db.config.js'); const Customer = db.customers; // Post a Customer exports.create = (req, res) => { // Save to MariaDB database Customer.create({ name: req.body.name, age: req.body.age, active: req.body.active }) .then(customer => { // Send created customer to client res.json(customer); }) .catch(error => res.status(400).send(error)) }; // Fetch all Customers exports.findAll = (req, res) => { Customer.findAll({ attributes: { exclude: ["createdAt", "updatedAt"] } }) .then(customers => { res.json(customers); }) .catch(error => res.status(400).send(error)) }; // Find a Customer by Id exports.findById = (req, res) => { Customer.findById(req.params.customerId, {attributes: { exclude: ["createdAt", "updatedAt"] }} ) .then(customer => { if (!customer){ return res.status(404).json({message: "Customer Not Found"}) } return res.status(200).json(customer) } ) .catch(error => res.status(400).send(error)); }; exports.lookUpByAge = (req, res) => { console.log("LookUByAge"); return Customer.findAll({ where: { age: req.params.age }, attributes: { exclude: ["createdAt", "updatedAt"] } }) .then( customers => { if(!customers){ return res.status(404).json({message: "Customers Not Found"}) } return res.status(200).json(customers) } ) .catch(error => res.status(400).send(error)); } // Update a Customer exports.update = (req, res) => { return Customer.findById(req.params.customerId) .then( customer => { if(!customer){ return res.status(404).json({ message: 'Customer Not Found', }); } return customer .update({ name: req.body.name, age: req.body.age, active: req.body.active }) .then(() => res.status(200).json(customer)) .catch((error) => res.status(400).send(error)); } ) .catch((error) => res.status(400).send(error)); }; // Delete a Customer by Id exports.delete = (req, res) => { return Customer .findById(req.params.customerId) .then(customer => { if(!customer) { return res.status(400).json({ message: 'Customer Not Found', }); } return customer.destroy() .then(() => res.status(200).json({message: "Destroy successfully!"})) .catch(error => res.status(400).send(error)); }) .catch(error => res.status(400).send(error)); }; exports.deleteAll = (req, res) => { return Customer.destroy({ where: {}, truncate: true }) .then(() => res.status(200).json({message: "All customers have been deleted!"})) .catch(error => res.status(400).send(error)); }
2.1.5 Server.js
var express = require('express'); var app = express(); var bodyParser = require('body-parser'); app.use(bodyParser.json()) const cors = require('cors') const corsOptions = { origin: 'http://localhost:4200', optionsSuccessStatus: 200 } app.use(cors(corsOptions)); const db = require('./app/config/db.config.js'); // force: true will drop the table if it already exists db.sequelize.sync({force: true}).then(() => { console.log('Drop and Resync with { force: true }'); }); require('./app/route/customer.route.js')(app); // Create a Server var server = app.listen(8080, function () { var host = server.address().address var port = server.address().port console.log("App listening at http://%s:%s", host, port) })
2.2 Angular 6 Client
2.2.0 Create Service & Components
Run commands below:
– ng g s Customer
– ng g c CreateCustomer
– ng g c CustomerDetails
– ng g c CustomersList
– ng g c SearchCustomers
On each Component selector, delete app-
prefix, then change tslint.json rules
– "component-selector"
to false.
2.2.1 Model
customer.ts
export class Customer { id: number; name: string; age: number; active: boolean; }
2.2.2 CustomerService
customer.service.ts
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class CustomerService { private baseUrl = 'http://localhost:8080/api/customers'; constructor(private http: HttpClient) { } getCustomer(id: number): Observable
2.2.3 Components
– CustomerDetailsComponent:
customer-details/customer-details.component.ts
import { Component, OnInit, Input } from '@angular/core'; import { CustomerService } from '../customer.service'; import { Customer } from '../customer'; import { CustomersListComponent } from '../customers-list/customers-list.component'; @Component({ selector: 'customer-details', templateUrl: './customer-details.component.html', styleUrls: ['./customer-details.component.css'] }) export class CustomerDetailsComponent implements OnInit { @Input() customer: Customer; constructor(private customerService: CustomerService, private listComponent: CustomersListComponent) { } ngOnInit() { } updateActive(isActive: boolean) { this.customerService.updateCustomer(this.customer.id, { name: this.customer.name, age: this.customer.age, active: isActive }) .subscribe( data => { console.log(data); this.customer = data as Customer; }, error => console.log(error)); } deleteCustomer() { this.customerService.deleteCustomer(this.customer.id) .subscribe( data => { console.log(data); this.listComponent.reloadData(); }, error => console.log(error)); } }
customer-details/customer-details.component.html
{{customer.name}}{{customer.age}}{{customer.active}}
– CustomersListComponent:
customers-list/customers-list.component.ts
import { Component, OnInit } from '@angular/core'; import { Observable } from 'rxjs'; import { CustomerService } from '../customer.service'; import { Customer } from '../customer'; @Component({ selector: 'customers-list', templateUrl: './customers-list.component.html', styleUrls: ['./customers-list.component.css'] }) export class CustomersListComponent implements OnInit { customers: Observable; constructor(private customerService: CustomerService) { } ngOnInit() { this.reloadData(); } deleteCustomers() { this.customerService.deleteAll() .subscribe( data => { console.log(data); this.reloadData(); }, error => console.log('ERROR: ' + error)); } reloadData() { this.customers = this.customerService.getCustomersList(); } }
customers-list/customers-list.component.html
Customers
– CreateCustomerComponent:
create-customer/create-customer.component.ts
import { Component, OnInit } from '@angular/core'; import { Customer } from '../customer'; import { CustomerService } from '../customer.service'; @Component({ selector: 'create-customer', templateUrl: './create-customer.component.html', styleUrls: ['./create-customer.component.css'] }) export class CreateCustomerComponent implements OnInit { customer: Customer = new Customer(); submitted = false; constructor(private customerService: CustomerService) { } ngOnInit() { } newCustomer(): void { this.submitted = false; this.customer = new Customer(); } save() { this.customerService.createCustomer(this.customer) .subscribe(data => console.log(data), error => console.log(error)); this.customer = new Customer(); } onSubmit() { this.submitted = true; this.save(); } }
create-customer/create-customer.component.html
Create Customer
You submitted successfully!
– SearchCustomersComponent:
search-customers/search-customers.component.ts
import { Component, OnInit } from '@angular/core'; import { Customer } from '../customer'; import { CustomerService } from '../customer.service'; @Component({ selector: 'search-customers', templateUrl: './search-customers.component.html', styleUrls: ['./search-customers.component.css'] }) export class SearchCustomersComponent implements OnInit { age: number; customers: Customer[]; constructor(private dataService: CustomerService) { } ngOnInit() { this.age = 0; } private searchCustomers() { this.dataService.getCustomersByAge(this.age) .subscribe(customers => this.customers = customers); } onSubmit() { this.searchCustomers(); } }
search-customers/search-customers.component.html
Find By Age
-
{{customer.id}} - {{customer.name}} {{customer.age}}
2.2.4 AppRoutingModule
app-routing.module.ts
import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { CustomersListComponent } from './customers-list/customers-list.component'; import { CreateCustomerComponent } from './create-customer/create-customer.component'; import { SearchCustomersComponent } from './search-customers/search-customers.component'; const routes: Routes = [ { path: '', redirectTo: 'customer', pathMatch: 'full' }, { path: 'customer', component: CustomersListComponent }, { path: 'add', component: CreateCustomerComponent }, { path: 'findbyage', component: SearchCustomersComponent }, ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { }
And AppComponent HTML for routing:
app.component.html
{{title}}
{{description}}
2.2.5 AppModule
app.module.ts
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { AppComponent } from './app.component'; import { CreateCustomerComponent } from './create-customer/create-customer.component'; import { CustomerDetailsComponent } from './customer-details/customer-details.component'; import { CustomersListComponent } from './customers-list/customers-list.component'; import { SearchCustomersComponent } from './search-customers/search-customers.component'; import { AppRoutingModule } from './app-routing.module'; import { HttpClientModule } from '@angular/common/http'; @NgModule({ declarations: [ AppComponent, CreateCustomerComponent, CustomerDetailsComponent, CustomersListComponent, SearchCustomersComponent ], imports: [ BrowserModule, FormsModule, AppRoutingModule, HttpClientModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
3. Run & Check Result
– Run Node.js project with commandlines: npm start
.
– Run the Angular App with command: ng serve
.
– Open browser for url http://localhost:4200/
:
Add Customer:
Show Customers:
Click on Active button to update Customer status:
Search Customers by Age:
Delete a Customer:
Delete All Customers:
IV. Source Code
– Nodejs-Express-Sequelizejs-MariaDB
– Angular6SpringBoot-Client