After studying some of the basics of Angular, this blog is dedicated to a simple Tutorial based on Angular with PHP backend and MySQL. As we all know that, Angular is a front-end framework. So, we need to require good technology that handles the backend operations. Here for the backend, we’re going to use MySQL for database and PHP. Also, we’re are using the Bootstrap 4 data table. So, we are going to start with how to use Angular with PHP backend
Install and Setup Angular App
First of all, let’s create an Angular app. Note that here please we need to make sure that we are using the latest version of Angular CLI.
We can check the Angular CLI version using the below command.
ng --version
Now, we are creating a new app using Angular CLI.
ng new angular-crud
Now, we are ready with the setup of your angular app.
Install Bootstrap 4 In Angular App
Now we need to move to the folder of our Angular App. For that, we can use the below command
cd angular-crud
Now we need to install bootstrap 4 in our Angular app using bootstrap 4 NPM package.
npm install bootstrap
Now open the angular.json file and add the bootstrap path to the styles section as I show below
"styles": [
"src/styles.css",
"node_modules/bootstrap/dist/css/bootstrap.min.css"
],
Install Bootstrap Datatable
Next, we are installing the bootstrap 4 data table in our Angular app using the below command
npm install angular-4-data-table-bootstrap-4 --save
Then, we need to import DataTableModule and other dependencies in our main module to start working with the data table.
/src/app/app.module.ts
//Other dependencies..
import { CommonModule } from '@angular/common';
//Import form modules
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
//Import DataTable Module
import { DataTableModule } from 'angular-4-data-table-bootstrap-4';
Here, don’t forget to add these modules in import sections as well.
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
CommonModule,
FormsModule,
ReactiveFormsModule,
DataTableModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Now our application is set to use data table, we can now run the application using below command
ng serve
Use PHP Backend + MySQL
Here, we are going to design the database design for our application. For that, we require a MySQL database. Here I am using Xampp. If you do not already install the Apache server, PHP and MySQL then install and continue. Now, I am going to create a separate new with our backend code.
Design MySQL Database
Now we are going to design a simple MySQL database and table. Let us go to phpmyadmin using the localhost and create a database named angular-crud. And now use the below query in your SQL for design a simple table named users.
CREATE TABLE `users` (
`id` int(11) NOT NULL,
`first_name` varchar(255) NOT NULL,
`last_name` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `users` (`id`, `first_name`, `last_name`) VALUES
(19, 'ABC', 'ABC'),
(21, 'XYZ', 'XYZ'),
Sorry I forget to use indexing, execute the below query as well
ALTER TABLE `users`
ADD PRIMARY KEY (`id`);
AUTO_INCREMENT for dumped tables
AUTO_INCREMENT for table `users`
ALTER TABLE `users`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
Design PHP Backend With API
Here, we are going to create a file that will interact with our Angular app. And there is a class that will interact with the database and we will handle the CRUD operations.
/php-rest-api/index.php
This above file will handle the requests coming and based on that call it will handle the database operations.
<?php
if (isset($_SERVER['HTTP_ORIGIN'])) {
header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
//If required
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Max-Age: 86400'); // cache for 1 day
}
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']))
header("Access-Control-Allow-Methods: GET, POST, PUT, OPTIONS");
if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']))
header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");
exit(0);
}
// Connecting to database
$conn = mysqli_connect('host','username','password','angular4-crud');
include_once('users.php');
$request_method = $_SERVER["REQUEST_METHOD"];
$data = json_decode(file_get_contents("php://input"));
$user = new Users;
switch($request_method)
{
case 'GET':
// Retrive Users
if(!empty($_GET["user_id"]))
{
$user_id=intval($_GET["user_id"]);
$user->getUsers($user_id);
}
else
{
$user->getUsers();
}
break;
case 'POST':
// Insert User
$user->saveUser($data);
break;
case 'PUT':
$user->updateUser($data);
break;
case 'DELETE':
// Delete User
$user->deleteUser($data);
break;
default:
// Invalid Request Method
header("HTTP/1.0 405 Method Not Allowed");
break;
}
/php-rest-api/users.php
The user's file will handle the database based operations on the call by index.php
<?php
class Users{
//Get users
function getUsers()
{
global $conn;
$query="SELECT * FROM users ORDER BY id DESC";
$response=array();
$result=mysqli_query($conn, $query);
while($row = mysqli_fetch_assoc($result))
{
$response[]=$row;
}
header('Content-Type: application/json');
echo json_encode($response);
}
//Save user
function saveUser($data){
global $conn;
$query="INSERT INTO users (first_name, last_name) VALUES ('".$data->first_name."', '".$data->last_name."')";
echo $result=mysqli_query($conn, $query);
header('Content-Type: application/json');
//Respond success / error messages
}
//Update user
function updateUser($data){
global $conn;
$query = "UPDATE users SET first_name='".$data->first_name."', last_name='".$data->last_name."' WHERE id=$data->id.";
echo $result=mysqli_query($conn, $query);
header('Content-Type: application/json');
//Respond success / error messages
}
//Delete user
function deleteUser($data){
global $conn;
$query = "DELETE FROM users WHERE id=".$data->id;
echo $result=mysqli_query($conn, $query);
header('Content-Type: application/json');
//Respond success / error messages
}
}
/php-rest-api/.htaccess
Now, we need .htaccess to hide the PHP extension from the URL.
RewriteEngine On
# Unless directory, remove trailing slash
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]+)/$ https://www.thetechieshouse.com/php-rest-api/$1 [R=301,L]
# Redirect external .php requests to extensionless url
RewriteCond %{THE_REQUEST} ^(.+)\.php([#?][^\ ]*)?\ HTTP/
RewriteRule ^(.+)\.php$ https://www.thetechieshouse.com/php-rest-api/$1 [R=301,L]
# Resolve .php file for extensionless php urls
RewriteRule ^([^/.]+)$ $1.php [L]
Note that If we are running PHP and Angular app both on your localhost, we will get some difficulties of CORS enabled or 405 or 401. Please check StackOverflow it will help you find the CORS issue.
Here we go, we are all set with our PHP backend code for our API.
Angular CRUD Example with PHP MySQL
Now, let us start writing the PHP APIs for our Angular app. So for this, we should define an Angular service that will handle the communication with PHP backend. Now we will define Angular Service. First of all, let us create a new service using Angular CLI.
ng generate service DbOperations
Now, let us design the service which will handle API calls.
/src/app/db-operations.service.ts
//Import Injectable
import { Injectable } from '@angular/core';
//Import http modules
import { Http, Response, Headers, RequestOptions } from '@angular/http';
//Import observable
import { Observable } from 'rxjs';
import 'rxjs/Rx';
@Injectable()
export class DbOperationsService {
apiURL = "https://www.thetechieshouse.com/php-rest-api";
constructor(private http: Http){}
//Save users
saveUsers(users: any[]){
console.log(users);
this.http.post(this.apiURL, users)
.subscribe(
(val) => {
console.log("POST call successful value returned in body",
val);
},
response => {
console.log("POST call in error", response);
},
() => {
console.log("The POST observable is now completed.");
});
}
//Get all users
getUsers() {
const headers = new Headers();
headers.append("Cache-Control", "no-cache");
headers.append('Access-Control-Allow-Origin', '*');
headers.append('Access-Control-Allow-Methods', 'GET, POST');
headers.append('Access-Control-Max-Age', '1728000');
headers.append('Content-Type', 'application/x-www-form-urlencoded');
return this.http.get(this.apiURL);
}
//Update user
updateUser(user)
{
return this.http.put(this.apiURL, user).subscribe(
(val) => {
console.log("UPDATE call successful value returned in body",
val);
},
response => {
console.log("UPDATE call in error", response);
},
() => {
console.log("The UPDATE observable is now completed.");
});
}
//Delete user
deleteUser(user){
return this.http.delete(this.apiURL, new RequestOptions({body : user
})).subscribe(
(val) => {
console.log("DELETE call successful value returned in body",
val);
},
response => {
console.log("DELETE call in error", response);
},
() => {
console.log("The DELETE observable is now completed.");
});
}
}
Here, we need to make sure that we are importing service and other our needed dependencies in your app main module.
/src/app/app.module.ts
//Import browser module
import { BrowserModule } from '@angular/platform-browser';
//Import core
import { NgModule } from '@angular/core';
//Import common
import { CommonModule } from '@angular/common';
//Import forms module
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
//Import DataTable
import { DataTableModule } from 'angular-4-data-table-bootstrap-4';
//Import HTTP for API call
import { HttpModule } from '@angular/http';
//Import app component
import { AppComponent } from './app.component';
//Import service
import { DbOperationsService } from './db-operations.service';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
CommonModule,
HttpModule,
FormsModule,
ReactiveFormsModule,
DataTableModule
],
providers: [DbOperationsService],
bootstrap: [AppComponent]
})
export class AppModule { }
Now, we are set with our service which will handle the API calls. Next, we will go to CRUD operations on Angular
List / Retrieve Operation
Firstly, let us define the app component and we need a template to work with the CRUD operations.
/src/app/app.component.ts
So we will import some of the dependencies in our app component. Next, let us have a class with a few of the basic methods which help to render the data table.
//Import core modules
import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';
//Import forms modules
import { FormGroup, FormControl, Validators} from '@angular/forms';
//Import DataTable
import { DataTableResource } from 'angular-4-data-table-bootstrap-4';
//Import HTTP
import { Http, Response, Headers } from '@angular/http';
//Import DB service
import { DbOperationsService } from './db-operations.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
title = 'Angular With PHP Backend ';
userForm: FormGroup;
@ViewChild('modalClose') modalClose:ElementRef;
persons: any[] = [];
itemResource;
items = [];
itemCount = 0;
params = {offset: 0, limit: 10}; //Static can be changed as per your need
formFlag = 'add';
constructor(private db:DbOperationsService, private http: Http){
//DB service function called
db.getUsers().subscribe(
(response: Response) => {
this.persons = response.json();
this.reloadItems(this.params);
} ,
(error) => {console.log(error);}
);;
}
reloadItems(params) {
this.itemResource = new DataTableResource(this.persons);
this.itemResource.count().then(count => this.itemCount = count);
this.itemResource.query(params).then(items => this.items = items);
}
// special properties:
rowClick(rowEvent) {
console.log('Clicked: ' + rowEvent.row.item.id);
}
rowDoubleClick(rowEvent) {
alert('Double clicked: ' + rowEvent.row.item.id);
}
rowTooltip(item) { return item.jobTitle; }
//Init method
ngOnInit(){
this.userForm = new FormGroup({
'id': new FormControl(null),
'first_name': new FormControl(null, Validators.required),
'last_name': new FormControl(null, Validators.required)
});
}
initUser(){
//User form reset
this.userForm.reset();
this.formFlag = 'add';
}
}
/src/app/app.component.html
Let us have a template with datatable and a modal popup which will add the values into the table. Also, we have used the reactive form approach for the validations.
<div style="margin: auto; max-width: 1000px; margin-bottom: 50px;">
<div class="modal fade" id="add-edit-Modal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Add/Edit Form</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<form [formGroup]="userForm" (ngSubmit)="saveUser(formFlag)">
<div class="modal-body">
<input type="hidden" class="input-sm form-control" formControlName="id">
<div class="form-group">
<input type="text" class="input-sm form-control" formControlName="first_name">
<p class="help-block" *ngIf="!userForm.get('first_name').valid && userForm.get('first_name').touched">Please enter first name.</p>
</div>
<div class="form-group">
<input type="text" class="input-sm form-control" formControlName="last_name">
<p class="help-block" *ngIf="!userForm.get('last_name').valid && userForm.get('last_name').touched">Please enter last name.</p>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" #modalClose data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary" [disabled]="!userForm.valid">Save changes</button>
</div>
</form>
</div>
</div>
</div>
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#add-edit-Modal" (click)="initUser()">Add</button>
<data-table id="persons-grid"
headerTitle="Angular CRUD Example With Bootstrap 4 Datatable"
[items]="items"
[itemCount]="itemCount"
(reload)="reloadItems($event)"
(rowClick)="rowClick($event)"
(rowDoubleClick)="rowDoubleClick($event)"
[rowTooltip]="rowTooltip"
>
<data-table-column
[property]="'first_name'"
[header]="'First Name'"
[sortable]="true"
[resizable]="true"
>
</data-table-column>
<data-table-column
[property]="'last_name'"
[header]="'Last Name'"
[sortable]="true"
>
</data-table-column>
<data-table-column
[property]="'Actions'"
[header]="'Actions'">
<template #dataTableCell let-item="item">
<span style="color: rgb(232, 0, 0)">
<a href="javascript:void(0);" (click)="getData(item)" data-toggle="modal" data-target="#add-edit-Modal">Edit</a>
</span>
<span style="color: rgb(232, 0, 0)">
<a href="javascript:void(0);" (click)="delData(item)">Delete</a>
</span>
</template>
</data-table-column>
</data-table>
</div>
Please don’t forget to mention our style for validations messages.
/src/app/app.component.css
input.ng-invalid.ng-touched {
border: 1px solid red;
}
p.help-block{
color: red !important;
}
.data-table-header{
text-align: center !important;
}
Create / Add and Edit / Update Operations
Here, we are using the same modal popup for add and edit operations by just switching it by using a formFlag.Based on our current flow, we are performing the service method call and then we will update the view.
//Save user's data
saveUser(){
if(this.formFlag == 'add')
{
this.userForm.value.id= this.persons.length + 1;
this.persons.unshift(this.userForm.value);
//Save method
this.db.saveUsers(this.userForm.value);
}
else
{
//Update database
this.db.updateUser(this.userForm.value);
var index = this.persons.findIndex(x => x.id== this.userForm.value.id);
if (index !== -1) {
this.persons[index] = this.userForm.value;
}
}
this.reloadItems(this.params);
//Close modal
this.modalClose.nativeElement.click();
//User form reset
this.userForm.reset();
}
//Get data while edit
getData(item)
{
//Here you can fetch data from database
this.userForm.patchValue(item);
this.formFlag = 'edit';
}
Delete Operation With DELETE Method
So, let us implement the delete operation. Here, we can use the confirmation pop up as per our need.
//Delete user's data
delData(item){
//Call service
this.db.deleteUser(item);
//Delete from array
this.persons.splice(this.persons.indexOf(item), 1);
this.reloadItems(this.params);
}
We are ready and we can run our application and enjoy it. Hope it helps you
Comments
Post a Comment