Building a Basic CRUD Application Using AngularJS and Slim PHP framework (Part 1)

I’ve been starting to learn and use AngularJS on some of my projects lately so I decided to share what I’ve learned so far.

AngularJS is an open-source JavaScript framework, maintained by Google, that assists with running single-page applications. Its goal is to augment browser-based applications with model–view–controller (MVC) capability, in an effort to make both development and testing easier.

According to Wikipedia

Today we’re going to create a basic CRUD application using AngularJS and the Slim PHP Framework. Slim a PHP micro framework that helps you create powerful web applications and APIs.

Let’s start by creating a new database name `angular_crud` then run the following SQL:

CREATE TABLE IF NOT EXISTS `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) NOT NULL,
  `first_name` varchar(100) NOT NULL,
  `last_name` varchar(100) NOT NULL,
  `address` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;

--
-- Sample Data
--

INSERT INTO `users` (`id`, `username`, `first_name`, `last_name`, `address`) VALUES
(1, 'lucentx', 'Aron', 'Barbosa', 'Manila, Philippines'),
(2, 'ozzy', 'Ozzy', 'Osbourne', 'England'),
(3, 'tony', 'Tony', 'Iommi', 'England');

I’ve added sample data in the sql file so it would be easier. Now let’s try to show those data on a webpage.
(This requires a web server installed. Checkout XAMPP, WAMP, etc.)

Download the files for the part 1 of the tutorial here then I’ll walk you through the code.

First let’s take a look at the index.html:

Take note of the two directives in the index.html file. On line 7 we have the ng-app directive, it is used to auto-bootstrap our angular application module which is the “CrudApp” in assets/js/app.js. Read more about ng-app here. The second directive is the ng-view directive. It will act as the view for our application.

Now let’s check out our angular app.

angular.module('CrudApp', []).
  config(['$routeProvider', function($routeProvider) {
  $routeProvider.
      when('/', {templateUrl: 'assets/tpl/lists.html', controller: ListCtrl}).
      when('/add-user', {templateUrl: 'assets/tpl/add-new.html', controller: AddCtrl}).
      otherwise({redirectTo: '/'});
}]);

function ListCtrl($scope, $http) {
  $http.get('api/users').success(function(data) {
    $scope.users = data;
  });
}

function AddCtrl($scope, $http, $location) {
  $scope.master = {};
  $scope.activePath = null;

  $scope.add_new = function(user, AddNewForm) {
    console.log(user);

    $http.post('api/add_user', user).success(function(){
      $scope.reset();
      $scope.activePath = $location.path('/');
    });

    $scope.reset = function() {
      $scope.user = angular.copy($scope.master);
    };

    $scope.reset();

  };
}

Line 1 to 7 is our CrudApp angular module. Here we have the application routes which are declared by $routeProvider. This service makes it easy to wire together controllers, view templates, and the current URL location in the browser. As you can see in line 4, it means that will use the assets/tpl/lists.html template and the ‘ListCtrl’ controller. Our ‘ListCtrl’ controller utilizes the scope and $http service.

scope is an object that refers to the application
model. It is an execution context for expressions. Scopes are arranged in hierarchical structure which mimic the DOM structure of the application. Scopes can watch expressions and propagate events.

The $http service is a core Angular service that facilitates communication with the remote
HTTP servers via the browser’s XMLHttpRequest object or via JSONP.

So for the the ‘ListCtrl’ controller, we’re trying to list all the users from the database using our angular app.

Using the $http service, we can send a get request for all the users in our database. That’s where slim php comes in. If you try to check api/index.php below:

require 'Slim/Slim.php';

$app = new Slim();
$app->get('/users', 'getUsers');
$app->post('/add_user', 'addUser');


$app->run();

function getUsers() {
  $sql = "select * FROM users ORDER BY id";
  try {
    $db = getConnection();
    $stmt = $db->query($sql);  
    $wines = $stmt->fetchAll(PDO::FETCH_OBJ);
    $db = null;
    echo json_encode($wines);
  } catch(PDOException $e) {
    echo '{"error":{"text":'. $e->getMessage() .'}}'; 
  }
}

function addUser() {
  $request = Slim::getInstance()->request();
  $user = json_decode($request->getBody());
  $sql = "INSERT INTO users (username, first_name, last_name, address) VALUES (:username, :first_name, :last_name, :address)";
  try {
    $db = getConnection();
    $stmt = $db->prepare($sql);  
    $stmt->bindParam("username", $user->username);
    $stmt->bindParam("first_name", $user->first_name);
    $stmt->bindParam("last_name", $user->last_name);
    $stmt->bindParam("address", $user->address);
    $stmt->execute();
    $user->id = $db->lastInsertId();
    $db = null;
    echo json_encode($user); 
  } catch(PDOException $e) {
    echo '{"error":{"text":'. $e->getMessage() .'}}'; 
  }
}

function getConnection() {
  $dbhost="127.0.0.1";
  $dbuser="root";
  $dbpass="";
  $dbname="angular_tutorial";
  $dbh = new PDO("mysql:host=$dbhost;dbname=$dbname", $dbuser, $dbpass);  
  $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  return $dbh;
}

we can see that when we request for api/users it will return the data in json format:

[{
  "id":"1",
  "username":"lucentx",
  "first_name":"Aron",
  "last_name":"Barbosa",
  "address":"Manila, Philippines"
},
{
  "id":"2",
  "username":"ozzy",
  "first_name":"Ozzy",
  "last_name":"Osbourne",
  "address":"England"
},
{
  "id":"3",
  "username":"tony",
  "first_name":"Tony",
  "last_name":"Iommi",
  "address":"England"
}]

The returned data is assigned to $scope.users in our ‘ListCtrl’ controller:

function ListCtrl($scope, $http) {
  $http.get('api/users').success(function(data) {
    $scope.users = data;
  });
}

Then we use ngRepeat to iterate the returned data into our template (assets/tpl/lists.html):

Viola! When we navigate to http://localhost/angular_crud/ on our browser we can see the listing like this:

angular lists

The same process goes for adding new users. When we navigate to http://localhost/angular_crud/#/add-user, via angular’s route service, it will load the assets/tpl/add-new.html template and we tell angular to use ‘AddCtrl’ controller.

As you can see on the code above we use the ngModel directive. We assign the values to the user model. If you noticed, the save button is disabled because I’ve added a ngDisabled directive to it so it won’t be enabled while the form has invalid values or is unchanged. This is part of angular’s form validation. When the form is valid, it will fire up the add_new function in our ‘AddCtrl’ controller as shown on line 5 below:

function AddCtrl($scope, $http, $location) {
  $scope.master = {};
  $scope.activePath = null;

  $scope.add_new = function(user, AddNewForm) {

    $http.post('api/add_user', user).success(function(){
      $scope.reset();
      $scope.activePath = $location.path('/');
    });

    $scope.reset = function() {
      $scope.user = angular.copy($scope.master);
    };

    $scope.reset();

  };
}

If the form is valid, it will send an http post request to our api. The our api will save the data to our database using the function below on our api/index.php file:

function addUser() {
	$request = Slim::getInstance()->request();
	$user = json_decode($request->getBody());
	$sql = "INSERT INTO users (username, first_name, last_name, address) VALUES (:username, :first_name, :last_name, :address)";
	try {
		$db = getConnection();
		$stmt = $db->prepare($sql);  
		$stmt->bindParam("username", $user->username);
		$stmt->bindParam("first_name", $user->first_name);
		$stmt->bindParam("last_name", $user->last_name);
		$stmt->bindParam("address", $user->address);
		$stmt->execute();
		$user->id = $db->lastInsertId();
		$db = null;
		echo json_encode($user); 
	} catch(PDOException $e) {
		echo '{"error":{"text":'. $e->getMessage() .'}}'; 
	}
}

Checkout the Slim framework documentation for more information. That’s all for today. Feel free to contact me if you have any questions or clarifications. Will continue this tutorial next time. I’ll show you how to do the update and delete on our application. Cheers!

This entry was posted in Blog and tagged , , , , . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.
  • http://unincredible.tumblr.com/ unincredible

    Thank you for this tutorial! This got me up and running using MySQL + Slim, which was the hurdle I was trying to overcome developing an Angular app on a host without MongoDB or root access.

    • lucentx

      You’re welcome! I’m glad it helped. Cheers!

  • Peter

    The add user does not persist the data to the database nor display it after clicking on save, not sure if this is related but I also seem to be getting a “Uncaught TypeError: Cannot call method ‘push’ of undefined” any clue what could be causing this.

  • Umair Ahmed

    Awesome !!!!

  • wihe

    I liked the tutorial. When launched the second part of the tutorial?

    Regards

  • Gabo Lato

    Great Blog man! Congrats!

  • http://desarrollowebinteligente.blogspot.ca/ Erick Moises Racancoj Amperez

    AWESOME, it’s a nice practice tutorial.
    I have som problems with an update.
    1. ERROR:{“error”:{“text”:SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens}}.
    2. TABLE: medico {idMedico int,Nombre varchar(50),Apellido varchar(50),Disponibilidad int,Estado tinyint(1)}
    3. SCRIPT:
    function editarMedico($id) {
    $request = Slim::getInstance()->request();
    $medicos = json_decode($request->getBody());
    $sql = “UPDATE medico SET Nombre=:Nombre, Apellido=:Apellido, Disponibilidad=:Disponibilidad WHERE idMedico=:id”;
    try {
    $db = getConnection();
    $stmt = $db->prepare($sql);
    $stmt->bindParam(“:Nombre”, $medicos->Nombre);
    $stmt->bindParam(“:Apellido”, $medicos->Apellido);
    $stmt->bindParam(“:Disponibilidad”, $medicos->Disponibilidad);
    $stmt->bindParam(“:id”, $id);
    $stmt->execute();
    $db = null;
    //echo ($medicos);
    echo json_encode($medicos);
    } catch(PDOException $e) {
    echo ‘{“error”:{“text”:’. $e->getMessage() .’}}’;
    }
    }
    Any clue what could be causing this? Thanks for helping me

  • Josh Blaha

    I’m getting a 404 when trying to access api/users. I didn’t see any download in order to go off of either. This will be pretty awesome when I get it working though.

    • http://leonardolima.info Leonardo Lima

      It is a URL rewriting issue. In this case, you just have to replace all occurrences of ‘api’ for ‘api/index.php’, obviously without single quotation marks, in the file assets/js/app.js.

      For more details see http://docs.slimframework.com/routing/rewrite/

      • Brian Lovely

        All rewriting the URL did for me was to change to error from a 404 code to a 500. Still can’t get the thing to work correctly. Using MAMP, have the database set up, and have slim installed in api/slim

  • Bhaall

    Do you get an error when deleting a user (function deleteUser in index.php)? The error seems to be the fetchAll statement:

    $wines = $stmt->fetchAll(PDO::FETCH_OBJ);

    The error (in Chrome’s ‘network’ panel):
    {“error”:{“text”:SQLSTATE[HY000]: General error}}

    This is also causing an error in angular (in Chrome’s console):
    SyntaxError: Unexpected token S

    • lio

      In this line :
      echo ‘{“error”:{“text”:’. $e->getMessage() .’}}’;
      change to =>
      echo ‘{“error”:{“text”:”‘. $e->getMessage() .'”}}’;

  • sudeep

    Thanks bro

  • Michel

    The full source code here: https://github.com/lucentx/angular-crud

    • Sami Akram

      Thanks a lot. Should be the top comment 🙂

  • Ken Mastar

    I followed all the steps in this tutorial with my own application, but I could not load the data from my PHP file and when i went to the Chrome console, I was told tell “Unexpected token at object parse”. What does it mean? and how can I fix this kind of problem? Thanks for advice.

  • Abdurehman Yousaf

    i have been created a crud app using angularjs and slip framework but using ui-router for client side routing , add a user successfully and also show all users successfully, but when i get a single record to update it dose’nt show , also problem with delete,Plz! help me?

    This is my index.php file
    response->headers->set(‘Content-Type’, ‘application/json’);

    // POST route
    $app->post(‘/assignment’,function () {
    global $app;
    $book_obj=json_decode($app->request->getBody());
    $bookName=$book_obj->bookName;
    $authorName=$book_obj->authorName;
    //$pass=$user_obj->password;
    mysql_query(“INSERT INTO `crud` (`bookName`, `authorName`) VALUES (‘$bookName’, ‘$authorName’);”);
    echo “Book has been created”;
    });

    // GET route
    $app->get(‘/assignment/’,function () {
    $books=mysql_query(“select * from crud”);
    $books_array = array();
    while($book_obj=mysql_fetch_object($books)){
    $books_array[] = $book_obj;
    }
    // print_r json_encode($books_array);
    print_r(json_encode($books_array));
    });

    // GET route
    $app->get(‘/assignment/:id’,function ($id) {
    $book=mysql_query(‘select * from crud where id=’.$id);
    print json_encode(mysql_fetch_object($book));
    });

    //PUT route
    $app->put(‘/assignment/:id’,function ($id) {
    global $app;
    $book_obj=json_decode($app->request->getBody());
    $bookName=$book_obj->bookName;
    $authorName=$book_obj->authorName;
    //$pass=$user_obj->pass;
    mysql_query(“UPDATE `crud`.`crud` SET `id`=’null’ ,`bookName`=’$bookName’ ,`authorName` = ‘$authorName’ WHERE `crud`.`id`= $id;”);
    echo “Book Record has been updated”;
    });
    // PUT route
    // $app->put(‘/:id’,function ($id) {
    // global $app;
    // $bookName=$app->request->put(“bookName”);
    // $authorName=$app->request->put(“authorName”);
    // mysql_query(“UPDATE `crud`.`crud` SET `bookName`=’$bookName’ ,`authorName` = ‘$authorName’ WHERE `crud`.`id`= $id;”);
    // });

    // DELETE route
    $app->delete(‘/assignment/:id’,function ($id) {
    mysql_query(‘DELETE FROM `crud` WHERE `id` =’. $id);
    });

    //returning response
    $app->run();

  • DLZ Tom

    There are almost all mentioned problems sourced from .htaccess file. See the original from GutHub it will works.

    • Carlos Ramirez Longoria

      i downloaded the project from github and i get a 500 internal server error 🙁

  • Seydina Omar Ibn Maryam

    great tutorial! just some corrections: in addUser method you have to do this: $request = SlimSlim::getInstance()->request(); to post data!

  • MZulkarnain Jaranee

    Nice and easy tutorial. Gonna try this on the weekend. Thanks!

  • Harry Martin

    Thats great blog. Suggest you to make use of FREE AngularJS tutorials which comes with 100% source code for Beginners. I hope you would find this tutorial interesting and helpful. You can get the link to download the tutorials here http://learnsauce.com/angularjstutorial/

  • Rohit Shrivastava

    function getConnection() {
    $dbhost=”127.0.0.1″;
    $dbuser=”root”;
    $dbpass=””;
    $dbname=”angular_crud”; //required changes
    $dbh = new PDO(“mysql:host=$dbhost;dbname=$dbname”, $dbuser, $dbpass);
    $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    return $dbh;
    }

    • Jamel ALOUI

      Hello,
      I change the name of the database but also the data (the list of users) does not appear, there is something else to do?
      Thank you in advance.

  • Tom van Tilburg

    Thanks for this. I just don’t get it to work in html5 mode. It’s no problem with the hashtag and hashprefix. ——– NEVERMIND

    To get this to work in html5Mode(true); use following .htaccess. don’t thank me, thank benjick : https://scotch.io/quick-tips/pretty-urls-in-angularjs-removing-the-hashtag

    RewriteEngine on

    # Don’t rewrite files or directories
    RewriteCond %{REQUEST_FILENAME} -f [OR]
    RewriteCond %{REQUEST_FILENAME} -d
    RewriteRule ^ – [L]

    # Rewrite everything else to index.html to allow html5 state links
    RewriteRule ^ index.html [L]

    if you want to get around the need of having to use api/index.php/ in app.js
    paste this .htaccess in your api folder

    RewriteEngine on

    # Don’t rewrite files or directories
    RewriteCond %{REQUEST_FILENAME} -f [OR]
    RewriteCond %{REQUEST_FILENAME} -d
    RewriteRule ^ – [QSA,L]

    # Rewrite everything else to index.php to remove the need of api/index.php in app.js
    RewriteRule ^ index.php [QSA,L]

    If anyone has a suggestion / improvement. Feel free to do so, I’ll edit my comment for you.

  • Tom Drozdowski

    I get this error and yes i tried to connect local angular.min.js – to no fruition
    ANY HELP ?

    Error: Access to restricted URI denied
    Yc/<@https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js:99:321
    n@https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js:95:1
    l@https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js:94:218…..

    …………. and so on an on

    • lucentx

      Hi, you should not access the file directly. From what I see on your screenshot, you should try accessing it like http://localhost/pew/index.html

      • Tom Drozdowski

        I’ll try this as soon as I get home. Thanks for quick answer and … again : very good tut and an usefull one. Cheers

  • lucentx

    Hi guys, I’ve updated the project to use the new version of Slim PHP framework. It’s on https://github.com/lucentx/angular-crud Feel free to create tickets or email me if you have any questions or suggestions. Thanks!

  • gugasevero

    Hi! How can I use this codes with php class?
    Thank you.

  • Ravi

    i’m Not Getting data from database to view. and whats Slim.php explain also.
    can u please help any one

  • schogini

    Excellent!! Thanks very much

  • Jamel ALOUI

    Hello,
    I am a beginner in AngularJS, I followed the tutorial, trying to realize it, the list of users does not appear (I have inserted them in the database), no error message. Can anyone help me? In fact I need to manipulate the data of a MySQL database (view, modify, add, delete) using AngularJS and Slim PHP Framework.
    The on-screen display is as follows:
    https://uploads.disquscdn.com/images/c4a1f0af73b9fcd546f6711d2e5bbec6c017c80483f925d304ecc8b0325cc7ed.jpg
    Thank you in advance.