AngularJS and Laravel Shopping List Application – Part 2

/ Javascript, PHP / by Paul Robinson / 47 Comments
This post was published back on July 2, 2013 and may be outdated. Please use caution when following older tutorials or using older code. After reading be sure to check for newer procedures or updates to code.

As promised here is the second part of building our Shopping List Application with the excellent AngularJS the JavaScript MVW framework. In this final part we are going to look at how to extend our application so that it can receive data (via JSON) from a REST based application to populate our shopping list with items. This is as opposed to the static method we have at the moment.

AngularJS + Laravel: Prerequisites

The most obvious prerequisite is that you have followed or at least read the first part of this tutorial. If you haven’t go back & read part one of our AngularJS tutorial now. I’ll wait for you. You back? Good.

AngularJS + Laravel: Notes

First a couple of notes. There are a couple of ways to do this. I’ve picked the simplest as it is a simple application & we don’t want to overcomplicate things. Also I’m going to show you how to set up a REST based application to feed data into our AngularJS app using Laravel. To do this you need a few things. Please note: Laravel requires PHP 5.3.7 & MCrypt to work.

First is Composer. Just go to the download page. If you are on Windows like me, get the Windows install & you should be done in no time. You may need to restart or at least log out for some changes to take effect so go on. I’ll wait again. Back? Good.

Now that you have Composer, let’s get on with setting up Laravel.

AngularJS + Laravel: Setting Up

There are two ways to do this. I prefer the slightly more manual method so we are going to follow that one. Get yourself a copy of the Master of Laravel from Github (Hit ‘Download ZIP’ on the bottom right) and extract it to a folder in your localhost. I’m using the folder name rest for this. Now I think I should explain how this is going to work first.

Instead of having Laravel running our AngularJS application and our REST system we are just going to have Laravel run our REST system. This keeps things simpler as this tutorial is more about AngularJS & not Laravel.

Now that you have Laravel in it’s folder let’s get it setup. Open a command prompt, or terminal and navigate to the directory you just extracted Laravel to. In my case the command looked like this:

That’s cd or ‘change directory’. Out 2 folders, into the xampp folder, htdocs and then rest. Now that you are there just run:

Then wait for a while as Composer installs Laravel & it’s dependencies.

All done? Good. Now you’ve done that we need to set a few more things up. First open up app/config/app.php and use a random string generator to get a 32 character string to place in the key field. Also update the url in here which will eventually be http://localhost/rest once we’ve setup an Alias.

Now rather than faff around with Virtual Hosts we are just going to set up an Alias. To do this open up your Apache httpd.conf file. In my case (using XAMPP) this is located at C:/xampp/apache/conf/httpd.conf. At around line 220 there is a block of code that starts with:

You want to copy that all the way down to the closing directory tag (</Directory>) and paste it directly underneath. Then change the path inside the directory tag to C:/xampp/htdocs/rest/public or whatever the path is to your Laravel public folder. Now look around line 340 for the <IfModule alias_module> tag and inside add:

Again change the path to your Laravel public folder if it is different. Now restart Apache using your web servers control panel to apply the changes. Finally open up the .htaccess file located in the Laravel public folder and make sure it matches the following:

Once you’ve done that visiting http://localhost/rest should give you the Laravel welcome page. If not try restarting Apache once more, if all else fails leave a comment and I’ll see if I can help out. These steps should be the same for all web servers using Apache, just the paths might be different.

AngularJS + Laravel: REST

Now we’ve set up Laravel we can move on to getting our REST app working. For this we’ll have to visit the command line a few more times. In Laravel open up app/config/database.php and enter your local Database details. Once you’ve done that go back to your command prompt (open one & navigate to the ‘rest’ folder if you closed it) and run:

This will make you a migration file. If it failed for some reason try these steps. Open it up from app/database/migrations now in the up function enter the following:

In the down function enter this:

This tells Laravel to create us a table with those fields when we run the migration. If we were to reverse it the it runs the down function which simply drops the table. This is used for versioning your modifications to database tables within Laravel & is very handy. That, however, is something for a Laravel tutorial so let’s move on.

Now back in the command prompt run:

This will create the table we need.

Now we need to enter some data so we can check things are working. We could use Laravel’s Seeding system, but to save complicating things just jump into your Database Admin (Normally PHPMyAdmin) and add some data manually. If you aren’t sure how to do that, don’t worry it just means you won’t be able to see any results until we’ve added in the ability to add items via our app. That’s perfectly fine though so don’t worry.

Now to do some CRUD (Create, Read, Update, Delete) on our table we need a Model so Laravel can access our table. Let’s make one. In app/models create a file called Item.php. Inside all you need is the following:

I’ve included the PHP tag just to show it is needed, but that’s all the code you need. The $timestamps variable is set just to tell Laravel we don’t want to use it’s automatic timestamp system. If you don’t add this Laravel will error because our table doesn’t include any fields for using timestamps, so make sure you leave it in there.

Now we just need to create our REST controller. Again at the command prompt run this:

Then open up your new controller found at app/controllers/ShoppingController.php. We are only going to use a few of the methods available here, but it is fine to leave the others for this demo. If you are using it in production I would remove the others. You are only going to need index, store, and destroy for this demo. First let’s take a look at index:

That’s all it is. This returns all of our items listed in some lovely clean JSON ready for AngularJS.

Next up is store:

This just grabs the name we have sent & saves it as a new item in the database. It also returns 1 or 0 to tell Angular if it saved successfully.

Finally is the destroy method:

All this does is find the item via the ID & deletes it.

The last thing we need to do is to setup some routing for Laravel. This is pretty simple, just open up app/routes.php, delete what you find and replace it with:

This will make it so if you visit http://localhost/rest/shop/ you will hopefully be faced with some JSON. You can also setup a method called missingMethod in your REST controller to catch any calls to unknown methods.

Now let’s setup a route to catch any visits to other URLs so that when we turn off debugging there will be a message shown to visitors. First still in app/routes.php type this above the route you just added:

This will tell Laravel to throw a 404 error for any url that doesn’t match shop. Then if you want to show a nice custom message you can open up app/start/global.php and add this above the Require The Filters File comment.

If you are more familiar with Laravel (again this is a AngularJS tutorial) you can return a view if you like, but this will do for this demo.

Phew! That’s our Laravel REST system complete, now we just need to tie our AngularJS code into it. Let’s do that now.

AngularJS + Laravel: $http

Now let’s get back to Angular. Reopen your app.js & index.html files from the last part.

First up we need to define our App this time. To do that in index.html change ng-app to ng-app="myApp". Then in app.js add this to the top of the file:

This defines our app & declares the SharedServices module as a dependency, we’ll define that next.

Under that code let’s add in that dependency. It actually allows us to add a nice loading spinner while our App retrieves the data. To do this we use a nice little snippet, I honestly don’t know who came up with this first but thank you however you are:

I don’t want to go into this code too much as it is outside of the scope of this tutorial, but it basically intercepts any requests made by the $http service and shows/hides a loader element as needed.

You may notice that this uses jQuery. Well since we don’t have it attached to our HTML file let’s do that. Above all our other scripts I’ve attached it using the Google CDN like this:

Again hosting it yourself is advised but this is fine for our demo. Next we need to add in the element it is using. Let’s add that in too. Again in your HTML file (index.html) find your ul and add a new li just above your ng-repeat. Like this:

Now I’m going to use a Canvas loader. To do this just add the Heartcode CanvasLoader to the page with your other script tags:

Then add the following code just before the closing body tag.

Then a little bit of CSS:

This is entirely optional, you can just add in a standard gif, but I like the new canvas option & though you’d might like it too.

Right, before we continue you need to know how you can access the REST controller’s different methods. It’s not as simple as calling them via URL such as rest/store. They have a special way to access them because of being a resource (as Laravel calls it) controller. Let’s take a look:

HTTP Verb url method
GET /rest/shop index
POST /rest/shop store
DELETE /rest/shop/:id destroy

These are just the ones we are using to keep it simple the others can be found over in Laravel’s documentation.

Now, you might be wondering why this section is subtitled $http, well we are getting to that now. I’m going to post all the new controller (ShopCtrl) code in one go this time as I think it would be too awkward to explain what has been changed:

You’ll probably be able to see the biggest change is the use of Angular’s $http service. Let’s go through each new part of this code. First the most important part that I’ve noticed causes a lot of bother.

Yep, there are lots of beginners that completely forget to send the $http service through and wonder why it doesn’t work. Well, in the infamous words of Adam Savage, “There’s your problem!”

Next up is the part that actually grabs the data from our REST service when the page loads.

So this is the extended version of using the $http service. It is not necessary to use this version here, but I thought I would in this demo to show what it looked like. Basically we give it the method (HTTP VERB), in this case GET, the URL to visit, in this case /rest/shop/, and we also want it to cache the data to save resources. Then we have two callbacks, if you are familiar with jQuery’s AJAX then you might feel at home with these. Basically if the request was successful we populate the $scope.items (the variable that holds all the shopping items, remember?) variable with the data. If there was an error, you would need to trigger something for the user to see. Again as this is just a demo I have just triggered a console log so I can see the status code. You could trigger a modal with an error in or a small text message, anything you like really.

Notice that the code we have just been talking about is just inside the controller & is not held in a method. This is because we want to trigger it as soon as the controller is called. I’ve seen some arguments about whether this is valid, but I haven’t had any trouble with it so I’d say go for it. If it makes you feel better though you can add it as a method of $scope & call it at the bottom of your app.js file to trigger everything off.

Next up is the new version of clearBought.

Now this probably isn’t the most efficient way to do this, but as we were using a REST service you can only pass 1 ID at a time so this is the best I could come up with. If you have another idea that is more efficient, answers on a postcard (or the comments) please.

All this code does is exactly the same as before. Filters out the items that have been bought, but this time as it is filtering we check if the current item has been bought & fire off a $http request to delete the item. This time I’m using the short version with the delete method. All you do is pass the URL, which in this case is /rest/shop plus the ID of the item we want to delete. Again I’ve added a error callback which just sends back the status code for debugging, but you’d want to add your own result to notify the visitor. Again a modal or something like that would be perfect.

Finally is the code to add a new item. This is the longest code so hold onto your hats, we’re going in.

So straight away we trigger $http this time using the post method, again we give it the url /rest/shop and this time we pass along some data. Note the lack of forward slash on the end of the URL. I’ve noticed if you add that in it will fail to add the item. In this case all we want is the text. How? Well the id & the bought value will be automatically be set to the correct values by the database as the ID is auto incremented & bought should be false by default.

Now in the success callback we check if our data was added, remember our Laravel method returns 1 on success, 0 on failure (0 is treated as falsy). The problem with this is that we need the ID that was created for the inserted item. To fix this go back to your Laravel application & open up app/controllers/ShoppingController.php and in the store method find:

Change it to:

This will send us back the ID created by the database when the item was inserted or 0 if it fails.

Now back to Angular. The last important line is:

This adds our new item to our array using the text from the text field again, automatically setting bought to false & using the ID we retrieved from Laravel (held in the data) variable. The rest of the code is just for error handling. Again I have console logs in there for debugging purposes but you could add some sort of modal to show visitors a friendly error.

AngularJS + Laravel: Artisan Doesn’t Work


This is normally because you are on a windows machine & PHP isn’t in your PATH environment variable. To solve this open an Windows Explorer window (the folder), right-click Computer and press ‘Properties’. Now click ‘Advanced System Settings’ on the left (Win 7 >), then press ‘Environment Variables’. In the bottom panel click Path, then click ‘Edit’. Now at the end of the 2nd text field enter a ; if there isn’t one there then type the path to the folder where PHP is held. If you are using XAMPP on your C drive this is normally C:\xampp\php\. That’s it.

You may need to restart or log out for the changes to take effect but normally you can just start using it without any problems.

AngularJS + Laravel: Summary

That’s it. It’s been a long tutorial but we’ve finally finished. If you reached this point you should now have a Shopping List application that is nearly identical to part 1, but it is now loading it’s data from an external source.

This is a huge tutorial so if you do have any problems please let me know in the comments & give me as much detail as you can about the issue you are having as it is pretty hard to debug without any error data. Unfortunately there is no demo for this part since, if this tutorial became popular, my server would hate me for it. If you are itching to see what it would look like though, use the demo in part 1.

As always thank you for reading. If you have any tips, suggestions or improvements I’m always happy to hear them. If you have any ideas for the kind of tutorials you’d like to see next, please post them on our Facebook wall or get in touch using Google Plus (links in the sidebar on the left).

47 Comments

Author’s gravatar

A really great set of tutorials… I had been struggling with connecting AngularJS to PHP and these tutorials made it really clear for me, thanks.

In the store piece of code I did have to change name to be text to line up with the fieldname i the database?

$input = Input::get(‘text’);

$item = new Item;
$item->text= $input;

Although I may have it wrong but my code works now 🙂

Reply
Author’s gravatar author

Hi Stephen,

Glad it helped. I must admit that connection Angular to PHP is a little difficult, it took a while to find a method that wasn’t too difficult to explain without a lecture, lol.

Nice spot. I had originally used different names for the variables & I hadn’t changed that. Thanks for pointing it out, I’ll change it now. 🙂

Author’s gravatar

Hello nice tutorial but I cant get some parts work as expected. I create a virtual host. I installed my laravel application. When I visit application.dev/shop I can see the Json array.

Where do I put index.html and app.js ? I cant get any views?

Reply
Author’s gravatar author

Hi Burak,

Your Angular app would be setup in another directory on your localhost. For example my local install I used http://localhost/angular/ for my Angular app, and http://localhost/rest/ for my Laravel install.

I apologise if that hadn’t been made clear in the tutorial.

Author’s gravatar

That is a great tutorial and is what I was looking for in combining Laravel + AngularJS…if I may give you a suggestion on your loop of removing the bought items, it might be better to just remove the chosen item on the spot when user is clicking on it, I mean why wait for the button “Remove Bought” and loop on each of them when you can remove the particular item when user is selecting it? Unless you really want to have the display still showing these bought items, but even then you could delete them from the DB and leave screen as is, after then if user refreshes his screen they’ll be gone, I would probably prefer this way actually, if user decide to put it back you could just re-push the same item in the DB.

Nice work again…

Reply
Author’s gravatar author

Hi Ghislain,

Unfortunately that idea violates the general features of a shopping list, or Todo app.

Leaving the items on the page allows the user to reference that they have already completed that task (Todo app) or bought the item (Shopping list).

Deleting the item, but leaving the item on the page risks problems with the item being permanently removed if the user loses signal or has an internet outage. It is also much more work to delete it, then re-push to the database than it is to just wait until they decide to clear the list.

As I have always said though, nothing is right or wrong. There are just different ideas on efficiency and ease of use. I personally prefer this setup, but would love to find a way to send a mass delete request to the REST API instead of looping through one at a time.

Author’s gravatar

it takes around 3seconds to load from the DB, dont you think thats very slow?

Reply
Author’s gravatar author

Hi,

There is something wrong with your database if it is taking that long. During my testing my local database was serving data almost instantly with a list of up to 40 items.

Author’s gravatar

Thank for your tutorial
I think it would be better to use $resource instead of $http in a Rest application.
Isn’t it?

Reply
Author’s gravatar author

Hi Hasan,

I’ve seen no evidence to suggest either way is better than the other (unless it has changed in a newer version of Angular), but whichever way you find the easiest or are familiar with would be the best way to go.

The aim of most of my tutorials is simply to teach those that don’t know, and nudge or help those that do in the correct direction. It isn’t to dictate what code you should & shouldn’t use.

Author’s gravatar

Lovely tut, thanks! Quick change to update the bought status in the db:

– add ng-change=”toggleBought(item.id, item.bought)” to the checkbox
– add the toggleBought function to the app:

– add the update function to the controller:

Reply
Author’s gravatar author

Hi,

Very nicely done. Would you mind if I added this to the article so that everyone can find it easily?

One small amendment, only for validation purposes, might be to pass Input::get('bought') through filter_var($input, FILTER_VALIDATE_BOOLEAN) to make sure it is a boolean. Mainly to keep validation purists happy. 😉

Again very well done & thank you for sharing it.

Author’s gravatar

Sure thing. My first stab at laravel & angular, was glad to find they slot together so neatly. Validation definitely!

Author’s gravatar

Hi – thank you for this great tutorial!

I am running into a problem with the clearBought() function.

For some reason, my code is treating items.bought as a string rather than an integer, and as a consequence it is removing items from $scope.items randomly, rahter than just the ones that have been marked as bought. Any idea what could be causing that?

Thanks!

Reply
Author’s gravatar

Sorry – I used the wrong snippet there. I added the ‘ == “1”‘ to get around the string problem and it seems to be working.

Author’s gravatar

The tutorial is great and is just what I have been looking for. I am having trouble with the laravel set up. It has to do with the Alias and .htaccess steps since when I run my laravel install using ‘php artisan serve’ the rest folder works on localhost:8000 and when I go to localhost:8000/shop I see the json read out from the database.

I am using osx with the local apache, php setup (and mysql is installed as well). My local machine url is localhost/~harberg/(folder name here), so for the angular portion I have it in a folder called shop, so localhost/~harberg/shop. When I open localhost/~harberg/rest I see the file directory (with the public folder missing). When I enter in localhost/~harberg/rest/public/ I get a 403 error. I have done a chmod to set the permissions at 777, but that hasn’t helped.

I tried just leaving the two folders (shop and rest) where they were working, but when I put the url of ‘localhost:8000/shop’ into the $http method of app.js I get an error in the console.

I would like to assume I am just missing something little, but any help would be great. Thanks.

Reply
Author’s gravatar

I got (anonymous function) in Delete Method

(anonymous function) angular.min.js:99
l angular.min.js:95
m angular.min.js:94
m.(anonymous function) angular.min.js:96
(anonymous function) app.js:37
w.filter.w.select underscore-min.js:1
ShopCtrl.$scope.clearBought app.js:35
(anonymous function) angular.min.js:72
(anonymous function) angular.min.js:143
e.$eval angular.min.js:88
e.$apply angular.min.js:88
$delegate.__proto__.$apply VM2506:855
(anonymous function) angular.min.js:143
x.event.dispatch jquery.js:5116
v.handle

Reply
Author’s gravatar

Can i use Laravel framework as frontend and angular js as a part . If yes? then how will i manage angular controller

Reply
Author’s gravatar author

Hi Rahul,

I’m not sure I understand. If you mean can you have Laravel run your app as well as the REST app, then sure. Just setup a second controller to serve your application & setup a route to match. It’s too complicated to explain here, but Laravel’s quickstart docs do a pretty good job of explaining what you would need to know to do that.

Author’s gravatar

Hi, your part 1 link is broken I suppose it gives 404 error

Reply
Author’s gravatar author

Hi,

Sorry about that. Thank you for letting me know. I’ve now corrected the link & it should be working again.

Author’s gravatar

Hi, I am doing one project in Laravel and AngularJS, PHP, Can you help me how to insert multiple records in one click submit.
I am sorry actually i am new to these technologies.
Ak

Please find the below code of Controller :

Find App.js Code :

Reply
Author’s gravatar author

Hi Akbar,

I’m not too sure I understand? Do you mean you would like to insert more than one record into your database on submit? If so you can use:

Just note that using that will insert the rows immediately (save does not need to be called) and can only be done if you have set a fillable or guarded property on your Eloquent Model.

Is that what you were looking for?

Author’s gravatar

Thanks for reply,
Yes i want to insert multiple records, because i am creating invoice form.
I am sorry i can’t understand your code please can explains as per my code.
Please don’t mind i am new to this.
Ak

Reply
Author’s gravatar author

Hi,

Laravel has two methods of creating new rows in your table. The way you are using, and the create() method that is available on your Eloquent Model.

Assuming that hostel_add is your Model name then you would use:

If your data comes comes from a POST request then you might want to run through your POST data using a for loop and create an array of arrays from your POST data and pass that straight to the create() method. There is more in Laravel’s docs under the section called Mass Assignment.

Does that help a little more?

Author’s gravatar

Thanks for reply,

I have to use loop to save multiple records.

Akbar

Author’s gravatar

Hi,
hostel_add is my model name.
I made a multi record form in html, once i submit the button it will trigger the create function in controller.
Akbar

Reply
Author’s gravatar author

Hi,

Then if you are sending all of the form results to your Laravel Controller you would use a foreach loop to go through each record and create an array of arrays containing the information in the format I used in the last comment. Then just pass that variable to your Model’s create method. It might look like:

This assumes you are already doing any validation you need to do on your data.

Does that help at all?

Author’s gravatar

Hi,
Thanks for reply,
You mean to say like this.

I am getting this error :\

Reply
Author’s gravatar author

Hi,

Assuming those are the correct keys, yes. The error is my fault, I forgot you said you were new to PHP and I missed the semi-colon out on the end of the array, that is line 16 in your example code. I’ve added it to my original comment just in case anyone else tries to copy to code and doesn’t notice the error.

Also you need to pass the array you generate to hostel_add::create() so that the rows are added to the database. If you don’t you’ll just create an array but nothing will be done in the database.

Author’s gravatar

Hi,

Yes, Thanks,
But not inserting the data, can you show me how to save the records.

Akbar

Reply
Author’s gravatar author

Hi,

As mentioned in my last reply, you just need to pass the array into hostel_add::create() and it should save.

Just to note that foreach loops, multi-dimensional arrays and Classes are some things in PHP that you should learn about before you jump into a complicated Framework such as Laravel. Without having an understanding of those basics it can be hard to understand how Laravel works.

I started out with a book by Apress way back but there are great guides on websites now. I would however recommend a book or a paid course on a website as self-teaching via tutorials can make you end up with bad habits.

Author’s gravatar

The below code is my controller which my masters teaching.
Please tell me clearly is this possible or not.

Code is:

Reply
Author’s gravatar

I need this part to below to insert multiple records.

public function create(){
if($this->data[‘users’]->role != “admin”) exit;

/*$bookLibrary = new hostel_add();
$bookLibrary->hostel_type = ‘Boys’; //Input::get(‘hostel_type’);
$bookLibrary->host_id = ‘1’; //Input::get(‘host_id’);
$bookLibrary->floor_name = Input::get(‘floor_name’);
$bookLibrary->room_no = Input::get(‘room_no’);
$bookLibrary->no_of_beds = Input::get(‘no_of_beds’);
$bookLibrary->amount_for = Input::get(‘amount_for’);
$bookLibrary->amount = Input::get(‘amount’);
$bookLibrary->save();*/

return $this->panelInit->apiOutput(true,$this->panelInit->language[‘gennotify’],$this->panelInit->language[‘genrecadd’],$bookLibrary->toArray() );
}

I am trying based on your suggestion but not inserting the records.

Akbar

Reply
Author’s gravatar

Hi,
Actually i got an assignment to make master detail forms like making invoice for every module.
Akbar

Reply
Author’s gravatar

Hi,
Please help me in this either give me any contact of good developer he can make invoice as per my system, i will pay if he want. Sorry to say this but i need very badly.

Akbar

Reply
Author’s gravatar author

Without any errors it is difficult to help, also please do not spam comments, I have to sleep and it was late when I replied to your previous message.

You need to create the array of arrays like I showed you previously, but I made a mistake and you need to use the insert method instead as Eloquent’s create method doesn’t accept a multidimensional array. Apologies. It’s been a little while since I’ve needed to do mass row insertions.

Code would be something like:

Again it may need tweaking. You will probably also need to include the Illuminate\Support\Facades\DB; namespace at the top of your file to allow you to use the DB facade

This assumes the data that is coming in is an array of records held in the POST superglobal under the key record. There are some many extra variables that could cause it to fail since I don’t know everything about your project.

From the questions you are asking I would guess you have only just started learning PHP? If so I would strongly suggest learning more about basic PHP before continuing with Laravel.

Author’s gravatar

Hi,
I am getting this error below:

[2017-05-12 12:17:42] local.ERROR: exception ‘Symfony\Component\Debug\Exception\FatalErrorException’ with message ‘Undefined constant ‘Illuminate\Support\Facades\DB” in D:\wamp\www\ESMS\app\controllers\HosteladdController.php:2
Stack trace:
#0 [internal function]: Illuminate\Exception\Handler->handleShutdown()
#1 {main} [] []
[2017-05-12 12:17:42] local.ERROR: exception ‘Symfony\Component\Debug\Exception\FatalErrorException’ with message ‘Undefined constant ‘Illuminate\Support\Facades\DB” in D:\wamp\www\ESMS\app\controllers\HosteladdController.php:2
Stack trace:
#0 [internal function]: Illuminate\Exception\Handler->handleShutdown()
#1 {main} [] []

Akbar

Reply
Older Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

I'll keep your WordPress site up-to-date and working to its best.

Find out more