Blog postAngular app with PHP backend: part 1

Learn to code Angular app with PHP backend: part 1

Published August 04, 2018

Angular is the most advanced and versatile frontend framework, but to build a full-blown application, you need a backend. In this series of tutorials, you will learn to code an Angular with a PHP backend.

The code in the first tutorial of the series fetches the data from the server side and then displays it in the Angular side of the application.

In the following tutorials, you'll learn how to add, update, and delete items.

Demo for the Angualr and PHP application

All the tutorials in the series about developing Angular app with a PHP backend:

  1. How to install Angular?
  2. What is REST API? In plain English
  3. What is Angular Observable?
  4. Angular app with PHP backend: part 1 (GET)
  5. Angular app with PHP backend: part 2 (POST)
  6. Angular app with PHP backend: part 3 (PUT)
  7. Angular app with PHP backend: part 4 (DELETE)

Click to see the code in action

You can dowload the source code from the conclusion section

# 1. Install Angular

If you do not know how to set up an Angular project, please read the Angular Installation guide I posted on the site.

To set up the project run the following two commands in the terminal:

> npm install -g @angular/cli

> ng new cars

The first command installs the Angular/CLI working environment, and the second generates a new Angular app with the name of cars.

Once the installation has finished, cd into the app's folder and then serve the app:

> cd cars/
> ng serve --o

It may take a while until the installation finishes and the app launches, but if everything is working according to plan you need to see Angular's default homepage:

Default homepage of an Angular app

To give the app a nice look, include the link to the Bootstrap's (CSS framework) stylesheet in the index.html header.

src/index.html

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Cars</title>
  <base href="/">
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
  <app-root></app-root>
</body>
</html>

Here I use a CDN as the source of the stylesheet.

# 2. Add the HttpClientModule to the project

Angular's preferred way to communicate with the server side is through the HttpClientModule module.

To be able to use the HttpClientModule, you need to import it into the root module of the application:

src/app/app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

It is not enough to import the module you should also add it's symbol to the imports array.

After importing, you will be able to use the module in the various parts of the application, such as in the components and services.

# 3. Add the Car class

A car is not just a thing, and since you work with TypeScript, you better define the type. You will do this with the Car class, which you need to add to the app. For this, manually create a car.ts file in the src/app folder, and put the following code inside:

src/app/car.ts

export class Car {
  constructor(
    model: string,
    price: number,
    id?:   number) {}
}

Besides the price and model name, the class contains an id which is an optional field, hence the question mark.

# 4. Place the method to communicate with the server in a service

While you can call AJAX directly from the components, this is not a best practice because you may want to use the same methods in different parts of the application. Therefore, it is better to put these methods in a dedicated service. In our case, it will be a service with the name of car.service.

To generate the service run the following command in the CLI:

> ng generate service app/car --flat --spec=false

The command includes two flags:

--flat because you want the service to contain only files instead of being locked in a folder.

--spec=false to prevent the generation of a unit test file.

Inside the generated file you will see the following code:

src/app/car.service.ts

import { Injectable } from '@angular/core';

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

The Injectable decorator allows the service to participate in the dependency injection system. Which means that on the one hand, it can have dependencies (i.e., the HttpClientModule module), and on the other hand, it can be injected, for example into the components.

But what is a dependency? A dependency is when one class depends on another for its function.

A dependency is when one class depends on another for its function.

Angular's way of managing the app dependencies is through the Dependency Injection system or DI, whose job it is to create for us the classes that we need in the right place at the right time.

A common practice of creating objects in object-oriented programming is by using the new keyword. For example, if you are interested in an HttpClientModule object, then you might be tempted to write the following code:

private http = new HttpClient;

But this is not the Angular way because when developing with Angular it is strongly advised to use the Dependency Injection system to manage the objects that the class needs.

when developing with Angular it is strongly advised to use the Dependency Injection system to manage the objects that the class needs.

For the CarService to function, it needs to inject the HttpClientModule dependency and import the various classes needed to manage the communication with the server.

Replace the code inside the service file with this:

src/app/car.service.ts

import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse, HttpParams } from '@angular/common/http';

import { Observable, throwError } from 'rxjs';
import { map, catchError } from 'rxjs/operators';

import { Car } from './car';

@Injectable({
  providedIn: 'root'
})
export class CarService {
  constructor(private http: HttpClient) { }
}

The dependency injection is done in the constructor, by defining the private HTTP variable as belonging to the HttpClient type, which instructs Angular to handle the creation of the HttpClient object for us by using the DI.

Importing from the RxJS library allows us to work with the Observable that Angular wraps around the data that is coming from the server. Using an Observable instead of a standard callback to handle asynchronous code offers several advantages, including multiple operators that facilitate data handling, as well as the ability to listen to data that the server emits repeatedly over time.

Want to know more about working with Observables in Angular? then read the tutorial What is Observable in Angular?

# 5. Displaying the list of cars coming from the server

To get the list of cars coming from the server, write the following code inside the class:

src/app/car.service.ts

baseUrl = 'http://localhost/api';
cars: Car[];
                
constructor(private http: HttpClient) { }
                
getAll(): Observable<Car[]> {
  return this.http.get(`${this.baseUrl}/list`).pipe(
    map((res) => {
      this.cars = res['data'];
      return this.cars;
  });
}

The getAll() method returns the list of cars wrapped in an Observable:

getAll(): Observable<Car[]> {
}

We use the HttpClient get() method to fetch the data from the server side:

getAll(): Observable<Car[]> {
  return this.http.get(`${this.baseUrl}/list`)
}

The data returned from the server is the list of cars wrapped inside an external array (a common case when consuming APIs).

This is how the data returned from the server looks like (we'll get to writing the code for the server side in a short time):

{
  data: 
  [
    {
      id: "1",
      model: "subaru",
      price: "120000"
    },
    {
      id: "2",
      model: "mazda",
      price: "160000"
    }
  ]
}

Since you are interested only in the list of cars in the innermost array you need to extract the list. For this job, you will use the RxJS pipe() operator that you need to chain to the get() method. Inside the pipe operator, you will map the array of cars that come from the server side to the service's local cars variable.

src/app/car.service.ts

getAll(): Observable<Car[]> {
  return this.http.get(`${this.baseUrl}/list`).pipe(
    map((res) => {
      this.cars = res['data'];
      return this.cars;
    });
}

So far, you've seen what to do when the data is OK, but what happens if the server side returns an error code. For example, 404, not found, or 500 in case of server error? In these cases, the getAll() method needs to call another one of Angular's methods, catchError():

src/app/car.service.ts

getAll(): Observable<Car[]> {
  return this.http.get(`${this.baseUrl}/list`).pipe(
    map((res) => {
      this.cars = res['data'];
      return this.cars;
  }),
  catchError(this.handleError));
}

catchError() has the parameter of the method that needs to handle the errors, handleError:

src/app/car.service.ts

private handleError(error: HttpErrorResponse) {
  console.log(error);
 
  // return an observable with a user friendly message
  return throwError('Error! something went wrong.');
}

The error handling includes the throwing of a general error message and a console.log() for debugging purposes.

Note that in order for the observable to work, it is not enough that you have the get() method in the service, you also need to actively send the data to the component.

# 6. The code in the component which subscribes to the data

To be able to display the data to the client, you need a method inside the component which subscribes to the data that the service fetches from the server. Write the following code inside the component file:

src/app/app.component.ts

import { Component, OnInit } from '@angular/core';

import { Car } from './car';
import { CarService } from './car.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  cars: Car[];
  error = '';
  success = '';
        
  constructor(private carService: CarService) {
  }
        
  ngOnInit() {
    this.getCars();
  }
        
  getCars(): void {
  }
}

The variable cars inside the component stores the array of cars retrieved from the server.

In the constructor, you inject the carService dependency so that the service will be available to all the methods of the controller as soon as Angular creates an object out of the controller.

Inside the ngOnInit() lifecycle hook, you call the getCars() method just after the creation of the controller by Angular.

ngOnInit is a special lifecycle hook provided by Angular that runs immediately after the constructor finishes injecting the dependencies, so it is a good place to get the array of cars into the controller.

Let's add the getCars() method that subscribers to the data that comes from the service:

src/app/app.component.ts

getCars(): void {
  this.carService.getAll().subscribe(
    (res: Car[]) => {
      this.cars = res;
    },
    (err) => {
      this.error = err;
    }
  );
}
  • The first callback is for handling the successful retrieval of the list of cars.
  • The second callback handles errors.

When we subscribe to observable we expect one of three results:

  • Getting the requested data from the server side (the array of cars).
  • An error on the server side.
  • An indication that the stream of data has finished.

In our case, only the first two results are relevant because the action is not expected to end since the list can be updated at any time with the items that our users add to the list (as you'll see in later tutorials).

Would you like to deepen your understanding of Observables? Read the tutorial that explains the subject in plain English.

And now all you have left is to show the HTML with the list of cars, and with the messages of success or error.

src/app/app.component.html

<div *ngIf="error">{{error}}</div>
<div *ngIf="success">{{success}}</div>
    
<div id="theList">
  <h2>The list</h2>
  <ul>
    <li *ngFor="let item of cars">{{item.model}} | {{item.price}} </li>
  </ul>
</div>

The list will be printed to the screen within the ngFor loop from the array of cars, once we set up the PHP backend server.

# 7. The server side of the project

I wrote server-side as a simple PHP script with a MySQL database. The same principles can be applied to any paradigm, framework or language.

For this tutorial I used XAMPP environment which runs on my computer.

The following is the MySQL code for generating the database table:

CREATE TABLE IF NOT EXISTS `cars` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `model` varchar(255) NOT NULL DEFAULT '',
  `price` int (10) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

Put the PHP scripts in a folder with the name of api/ on the server.

The .htaccess file is the configuration file of the Apache server, in which you specify two rules:

  1. A rule to remove the PHP extension from the file names.
  2. Headers to allow the Angular part of the application to transfer data and perform operations on the PHP server.

api/.htaccess

# Remove the php extension from the filename
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.php [NC,L]

# Set the headers for the restful api
Header always set Access-Control-Allow-Origin http://localhost:4200
Header always set Access-Control-Max-Age "1000"
Header always set Access-Control-Allow-Headers "X-Requested-With, Content-Type, Origin, Authorization, Accept, Client-Security-Token, Accept-Encoding"
Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS, DELETE, PUT"

The header part of the .htacess file:

Header always set Access-Control-Allow-Origin "http://localhost:4200"

Instructs the server to give the Angular app the necessary privileges even though the web address is different.

The rest of the headers permit the exchange of data between the Angular side and the server side using the HTTP protocol methods:

GET

To retrieve the data about a single resource* or a list of resources

POST

To store a new resource

PUT

To update the data that is already found on the server

DELETE

To destroy a resource

* A resource is roughly equivalent to a single row in the database. In our app, every car is a resource.

The application conforms to the REST API architecture on which you can read in the following tutorial.

The connect.php script creates the connection with the database:

api/connect.php

<?php

// db credentials
define('DB_HOST', 'localhost');
define('DB_USER', 'root');
define('DB_PASS', '');
define('DB_NAME', 'angular_db');

// Connect with the database.
function connect()
{
  $connect = mysqli_connect(DB_HOST ,DB_USER ,DB_PASS ,DB_NAME);

  if (mysqli_connect_errno($connect)) {
    die("Failed to connect:" . mysqli_connect_error());
  }

  mysqli_set_charset($connect, "utf8");

  return $connect;
}

$con = connect();

The api/list.php script receives a GET request from the Angular side of the application and returns the list of cars stored in the database.

list.php

<?php
/**
 * Returns the list of cars.
 */
require 'connect.php';
    
$cars = [];
$sql = "SELECT id, model, price FROM cars";

if($result = mysqli_query($con,$sql))
{
  $cr = 0;
  while($row = mysqli_fetch_assoc($result))
  {
    $cars[$cr]['id']    = $row['id'];
    $cars[$cr]['model'] = $row['model'];
    $cars[$cr]['price'] = $row['price'];
    $cr++;
  }
    
  echo json_encode(['data'=>$cars]);
}
else
{
  http_response_code(404);
}

# Conclusion

In the first tutorial in the series about developing an Angular and PHP application, we laid the foundations for building the app. We explained what is a service and why it is a good thing to put the methods that communicate with the server in a dedicated service. You learned about the HttpClientModule that Angular uses to communicate data via AJAX and that it is based on the pattern of Observable. We also started writing the code for the PHP backend which supplies the API for the app.

In the following tutorial, you will learn how to add new items to the list with the help of the post() method.

Click to download the source code for the tutorials

comments powered by Disqus