laravel-angular-single-page-comment-application
PHP

Create a Laravel and Angular Single Page Comment Application

Laravel and Angular have both become very well renowned tools in the web development world lately. Laravel for the great things it brings to the PHP community and Angular for the amazing frontend tools and its simplicity. Combining these two great frameworks only seems like the logical next step.

For our use cases, we will be using Laravel as the RESTful API backend and Angular as the frontend to create a very simple single page comment application.

This will be a simple example to show off how to get started using these two technologies so don’t hope for any extra database stuff on how to handle sub-comments or anything like that.

What We’ll Be Building

This will be a simple single page comment application:

  • RESTful Laravel API to handle getting, creating, and deleting comments
  • Angular frontend to handle showing our creation form and the comments
  • Ability to create a comment and see it added to our list w/o page refresh
  • Ability to delete a comment and see it removed from our list w/o page refresh

Overall, these are very simple concepts. Our focus will be to see the intricacies of how Laravel and Angular can work together.

laravel-angular-single-page-application

The Laravel Backend

Setting Up Laravel

Go ahead and get your Laravel setup ready. We’ll be doing some basic things to get our backend to do CRUD on comments:

  • Create a database migration
  • Seed our database with sample comments
  • Create our routes for our API
  • Creating a catch-all route to let Angular handle routing
  • Creating a resource controller for comments

Getting our Database Ready Migrations

We will need a simple structure for our comments. We just need text and author. Let’s create our Laravel migration to create our comments.

Let’s run the artisan command that will create our comments migration so that we can create the table in our database:

php artisan migrate:make create_comments_table --create=comments

We’ll use the Laravel Schema Builder to create the text and author fields that we need. Laravel will also create the id column and the timestamps so that we know how long ago the comment was made. Here is the code for the comments table:

	// app/database/migrations/####_##_##_######_create_comments_table.php
...

	/**
	 * Run the migrations.
	 *
	 * @return void
	 */
	public function up()
	{
		Schema::create('comments', function(Blueprint $table)
		{
			$table->increments('id');

			$table->string('text');
			$table->string('author');

			$table->timestamps();
		});
	}
...
	
	

Make sure you go adjust your database settings in app/config/database.php with the right credentials. Now we will run the migration so that we create this table with the columns that we need:

php artisan migrate

laravel-angular-migrate

With our table made, let’s create an Eloquent model so that we can interact with it.

Comment Model

We will be using Laravel Eloquent models to interact with our database. This will be very easy to do. Let’s create a model: app/models/Comment.php.

	
<?php

// app/models/Comment.php

class Comment extends Eloquent {
        // let eloquent know that these attributes will be available for mass assignment
	protected $fillable = array('author', 'text'); 
}

	
	

We now have our new table and model. Let’s fill it with some sample data using Laravel Seeding.

Seeding Our Database

We will need a few comments so that we can test a few things. Let’s create a seed file and fill our database with 3 sample comments.

Create a file: app/database/seeds/CommentTableSeeder.php and fill it with this code.

	
<?php
// app/database/seeds/CommentTableSeeder.php

class CommentTableSeeder extends Seeder 
{

	public function run()
	{
		DB::table('comments')->delete();

		Comment::create(array(
			'author' => 'Chris Sevilleja',
			'text' => 'Look I am a test comment.'
		));

		Comment::create(array(
			'author' => 'Nick Cerminara',
			'text' => 'This is going to be super crazy.'
		));

		Comment::create(array(
			'author' => 'Holly Lloyd',
			'text' => 'I am a master of Laravel and Angular.'
		));
	}

}
	
	

To call this Seeder file, let’s open app/database/seeds/DatabaseSeeder.php and add the following:

	// app/database/seeds/DatabaseSeeder.php
...

	/**
	 * Run the database seeds.
	 *
	 * @return void
	 */
	public function run()
	{
		Eloquent::unguard();

		$this->call('CommentTableSeeder');
		$this->command->info('Comment table seeded.');
	}

...
	
	

Now let’s run our seeders using artisan.

php artisan db:seed

laravel-angular-database-seed

Now we have a database with a comment table, an Eloquent model, and samples in our database. Not bad for a day’s work… but we’re not even close to done yet.

Comment Resource Controller app/controllers/CommentController.php

We will use Laravel’s resource controllers to handle our API functions for comments. Since we’ll be using Angular to display a resource and show create and update forms, we’ll create a resource controller with artisan without the create or edit functions.

Let’s create our controller using artisan.

php artisan controller:make CommentController --only=index,store,destroy

For our demo app, we’ll only be using these three functions in our resource controller. To expand on this you’d want to include all the functions like update, show, update for a more fully fledged app.

laravel-angular-create-controller

Now we’ve created our controller. We don’t need the create and edit functions because Angular will be handling showing those forms, not Laravel. Laravel is just responsible for sending data back to our frontend. We also took out the update function for this demo just because we want to keep things simple. We’ll handle creating, showing, and deleting comments.

To send data back, we will want to send all our data back as JSON. Let’s go through our newly created controller and fill out our functions accordingly.

	
<?php
// app/controllers/CommentController.php

class CommentController extends \BaseController {

	/**
	 * Send back all comments as JSON
	 *
	 * @return Response
	 */
	public function index()
	{
		return Response::json(Comment::get());
	}

	/**
	 * Store a newly created resource in storage.
	 *
	 * @return Response
	 */
	public function store()
	{
		Comment::create(array(
			'author' => Input::get('author'),
			'text' => Input::get('text')
		));

		return Response::json(array('success' => true));
	}

	/**
	 * Remove the specified resource from storage.
	 *
	 * @param  int  $id
	 * @return Response
	 */
	public function destroy($id)
	{
		Comment::destroy($id);

		return Response::json(array('success' => true));
	}

}
	
	

You can see how easy it is to handle CRUD with Laravel and Eloquent. It’s incredibly simple to handle all the functions that we need.

With our controller ready to go, the last thing we need to do for our backend is routing.

Extra Reading: Simple Laravel CRUD with Resource Controllers

Our Routes app/routes.php

With our database ready to rock and roll, let’s handle the routes of our Laravel application. We will need routes to send users to the Angular frontend since that will have its own routing. We will also need routes for our backend API so people can access our comment data.

Let’s create the Angular pointing routes. We will need one for the home page and a catch-all route to send users to Angular. This ensures that any way a user accesses our site, they will be routed to the Angular frontend.

We’ll be prefixing our API routes with… (drumroll please)… api. This way, if somebody wants to get all comments, they will use the URL: http://example.com/api/comments. This just makes sense moving forward and is some basic API creation good tactics.

	

<?php
// app/routes.php

// =============================================
// HOME PAGE ===================================
// =============================================
Route::get('/', function()
{
	// we dont need to use Laravel Blade
	// we will return a PHP file that will hold all of our Angular content
	// see the "Where to Place Angular Files" below to see ideas on how to structure your app
	return View::make('index'); // will return app/views/index.php
});

// =============================================
// API ROUTES ==================================
// =============================================
Route::group(array('prefix' => 'api'), function() {

	// since we will be using this just for CRUD, we won't need create and edit
	// Angular will handle both of those forms
	// this ensures that a user can't access api/create or api/edit when there's nothing there
	Route::resource('comments', 'CommentController', 
		array('only' => array('index', 'store', 'destroy')));
});

// =============================================
// CATCH ALL ROUTE =============================
// =============================================
// all routes that are not home or api will be redirected to the frontend
// this allows angular to route them
App::missing(function($exception)
{
	return View::make('index');
});

	
	

We now have our routes to handle the 3 main things our Laravel backend needs to do.

Handling Catch-All Routes: In Laravel, you can do this a few ways. Usually it isn’t ideal to do the above code and have a catch-all for your entire application. The alternative is that you can use Laravel Controller Missing Methods to catch routes.

Testing All Our Routes Let’s make sure we have all the routes we need. We’ll use artisan and see all our routes:

php artisan routes

This command will let us see our routes and sort of a top-down view of our application.

laravel-angular-artisan-routes

We can see the HTTP verb and the route used to get all comments, get a single comment, create a comment, and destroy a comment. On top of those API routes, we can also see how a user get routed to our Angular application by the home page route.

Backend Done

Finally! Our Laravel API backend is done. We have done so much and yet, there’s still so much to do. We have set up our database and seeded it, created our models and controllers, and created our routes. Let’s move onto the frontend Angular work.

Where to Place Angular Files

I’ve seen this question asked a lot. Where exactly should I be putting Angular files and how does Laravel and Angular work together. We did an article on getting Laravel Blade and Angular to work together. This article works under the assumption that we aren’t even going to use Blade.

To let Angular handle the frontend, we will need Laravel to pass our user to our index.php file. We can place this in a few different places. By default, when you use:

	// app/routes.php
Route::get('/', function() {

	return View::make('index');	

});
	
	

This will return app/views/index.php. Laravel will by default look in the app/views folder.

Some people may want to keep Angular files completely separate from Laravel files. They will want their entire application to be housed inside of the public folder. To do this is simple: just change the default View location to the public folder. This can be done in the app/config/view.php file.

	// app/config/view.php
...
	
	// make laravel look in public/views for view files
	'paths' => array(__DIR__.'/../../public/views'),

...
	
	

Now return View::make('index') will look for public/views/index.php. It is all preference on how you’d like to structure your app. Some people see it as a benefit to have the entire Angular application in the public folder so that it is easier to handle routing and if it is needed in the future, to completely separate the backend RESTful API and the Angular frontend.

For Angular routing, then your partial files will be placed in the public folder, but that’s out of the scope of this article. For more information on that kind of single page Angular routing, check out Single Page Angular Application Routing.

Let’s assume we left everything default and our main view file is in our app/views folder and move forward.

Routing with Laravel and Angular There are a lot of questions about having routing with Laravel and Angular and if they conflict. Laravel will handle the main routing for your application. Angular routing will only happen when Laravel routes our user to the main Angular route (index.php) in this case. This is why we use a Laravel catch-all route. Laravel will handle the API routes and anything it doesn’t know how to route will be sent to Angular. You can then set up all the routing for your Angular application to handle showing different views.

The Angular Frontend

Getting Our Application Ready

Everything for our Angular application will be handled in the public folder. This let’s us keep a good separation of the backend in the app folder.

Let’s look at the application structure we will have in our public folder. We’ve created our Angular application to be modular since that is best practices. Now our separated parts of our application will be easy to test and work with.

	
- public/
----- js/
---------- controllers/				// where we will put our angular controllers
--------------- mainCtrl.js 
---------- services/	 			// angular services
--------------- commentService.js 
---------- app.js
	
	

Angular Service public/js/services/commentService.js

Our Angular service is going to be the primary place where we will have our HTTP calls to the Laravel API. It is pretty straightforward and we use the Angular $http service.

	// public/js/services/commentService.js
angular.module('commentService', [])

	.factory('Comment', function($http) {

		return {
			// get all the comments
			get : function() {
				return $http.get('/api/comments');
			},

			// save a comment (pass in comment data)
			save : function(commentData) {
				return $http({
					method: 'POST',
					url: '/api/comments',
					headers: { 'Content-Type' : 'application/x-www-form-urlencoded' },
					data: $.param(commentData)
				});
			},

			// destroy a comment
			destroy : function(id) {
				return $http.delete('/api/comments/' + id);
			}
		}

	});
	
	

This is our Angular service with 3 different functions. These are the only functions we need since they will correspond to the api routes we made in our Laravel routes.

We will be returning the promise object from our service. These will be dealt with in our controllers. The naming convention here also stays the same as the Laravel controller that we have.

With our Angular Service done, let’s go into our controller and use it.

Angular Controller public/js/controllers/mainCtrl.js

The controller is where we will have most of the functionality for our application. This is where we will create functions to handle the submit forms and deleting on our view.

	// public/js/controllers/mainCtrl.js
angular.module('mainCtrl', [])

	// inject the Comment service into our controller
	.controller('mainController', function($scope, $http, Comment) {
		// object to hold all the data for the new comment form
		$scope.commentData = {};

		// loading variable to show the spinning loading icon
		$scope.loading = true;

		// get all the comments first and bind it to the $scope.comments object
		// use the function we created in our service
		// GET ALL COMMENTS ====================================================
		Comment.get()
			.success(function(data) {
				$scope.comments = data;
				$scope.loading = false;
			});

		// function to handle submitting the form
		// SAVE A COMMENT ======================================================
		$scope.submitComment = function() {
			$scope.loading = true;

			// save the comment. pass in comment data from the form
			// use the function we created in our service
			Comment.save($scope.commentData)
				.success(function(data) {

					// if successful, we'll need to refresh the comment list
					Comment.get()
						.success(function(getData) {
							$scope.comments = getData;
							$scope.loading = false;
						});

				})
				.error(function(data) {
					console.log(data);
				});
		};

		// function to handle deleting a comment
		// DELETE A COMMENT ====================================================
		$scope.deleteComment = function(id) {
			$scope.loading = true; 

			// use the function we created in our service
			Comment.destroy(id)
				.success(function(data) {

					// if successful, we'll need to refresh the comment list
					Comment.get()
						.success(function(getData) {
							$scope.comments = getData;
							$scope.loading = false;
						});

				});
		};

	});
	
	

As you can see in our controller, we have injected our Comment service and use it for the main functions: get, save, and delete. Using a service like this helps to not pollute our controller with $http gets and puts.

Connecting Our Application public/js/app.js

On the Angular side of things, we have created our service and our controller. Now let’s link everything together so that we can apply it to our application using ng-app and ng-controller.

This will be the code to create our Angular application. We will inject the service and controller into. This is best practices since it keeps our application modular and each different part can be testable and extendable.

	// public/js/app.js
var commentApp = angular.module('commentApp', ['mainCtrl', 'commentService']);
	
	

That’s it! Not much to it. Now we’ll actually get to our view where we can see how all these Angular parts work together.

Our Main View app/views/index.php

So far, after everything we’ve done up to this point, we still won’t be able to see anything in our browser. We will need to define our view file since Laravel in our home route and our catch-all route returns return View::make('index');.

Let’s go ahead and create that view now. We will be using all the Angular parts that we’ve created. The main parts that we’ve created from Angular that we’ll use in index.php are:

  • ng-app and ng-controller: We’ll apply these to our application by attaching them to our body tag
  • ng-repeat: We’ll loop over the comments and display them in our template
  • submitComment(): We’ll attach this function to our form using ng-submit
  • Loading Icons: We’ll create a variable called loading. If it is set to true, we’ll show a loading icon and hide the comments
  • deleteComment(): We’ll attach this function to a delete link so that we can remove the comment

Now let’s get to the actual code for our view. We’ll comment out the main important parts so we can see how everything works together.

	<!-- app/views/index.php -->
<!doctype html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Laravel and Angular Comment System</title>

	<!-- CSS -->
	<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.0/css/bootstrap.min.css"> <!-- load bootstrap via cdn -->
	<link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css"> <!-- load fontawesome -->
	<style>
		body 		{ padding-top:30px; }
		form 		{ padding-bottom:20px; }
		.comment 	{ padding-bottom:20px; }
	</style>

	<!-- JS -->
	<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
	<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.8/angular.min.js"></script> <!-- load angular -->

	<!-- ANGULAR -->
	<!-- all angular resources will be loaded from the /public folder -->
		<script src="js/controllers/mainCtrl.js"></script> <!-- load our controller -->
		<script src="js/services/commentService.js"></script> <!-- load our service -->
		<script src="js/app.js"></script> <!-- load our application -->

</head>
<!-- declare our angular app and controller -->
<body class="container" ng-app="commentApp" ng-controller="mainController">
<div class="col-md-8 col-md-offset-2">

	<!-- PAGE TITLE =============================================== -->
	<div class="page-header">
		<h2>Laravel and Angular Single Page Application</h2>
		<h4>Commenting System</h4>
	</div>

	<!-- NEW COMMENT FORM =============================================== -->
	<form ng-submit="submitComment()"> <!-- ng-submit will disable the default form action and use our function -->

		<!-- AUTHOR -->
		<div class="form-group">
			<input type="text" class="form-control input-sm" name="author" ng-model="commentData.author" placeholder="Name">
		</div>

		<!-- COMMENT TEXT -->
		<div class="form-group">
			<input type="text" class="form-control input-lg" name="comment" ng-model="commentData.text" placeholder="Say what you have to say">
		</div>
		
		<!-- SUBMIT BUTTON -->
		<div class="form-group text-right">	
			<button type="submit" class="btn btn-primary btn-lg">Submit</button>
		</div>
	</form>

	<!-- LOADING ICON =============================================== -->
	<!-- show loading icon if the loading variable is set to true -->
	<p class="text-center" ng-show="loading"><span class="fa fa-meh-o fa-5x fa-spin"></span></p>

	<!-- THE COMMENTS =============================================== -->
	<!-- hide these comments if the loading variable is true -->
	<div class="comment" ng-hide="loading" ng-repeat="comment in comments">
		<h3>Comment #{{ comment.id }} <small>by {{ comment.author }}</h3>
		<p>{{ comment.text }}</p>

		<p><a href="#" ng-click="deleteComment(comment.id)" class="text-muted">Delete</a></p>
	</div>

</div>
</body>
</html>
	
	

laravel-angular-single-page-application

Now we finally have our view that brings all of the parts we created together. You can go ahead and play around with the application. All the parts should fit together nicely and creating and deleting comments should be done without a page refresh.

Testing the Application

Make sure you take a look at the Github repo to test the application. Here are some quick instructions to get you going.

  1. Clone the repo: git clone [email protected]:scotch-io/laravel-angular-comment-app
  2. Install Laravel: composer install --prefer-dist
  3. Change your database settings in app/config/database.php
  4. Migrate your database: php artisan migrate
  5. Seed your database: php artisan db:seed
  6. View your application in the browser!

Conclusion

Hopefully this tutorial gives a good overview of how to start an application using Laravel and Angular. You can bring this farther and create a full application that can handle multiple API calls on the Laravel side, and even create your own Angular routing for multiple pages.

Sound off in the comments if you have any questions or would like to see a specific use case. We can also expand on this demo and start adding different things like editing a comment, user profiles, whatever.

Design, development, and anything in between that I find interesting.

View My Contributions

Stay Connected With Us
hover these for magic

Get valuable tips, articles, and resources straight to your inbox. Every Tuesday.

  • Mike

    The only problem I found was when trying to create a comment. I was getting an internal server error with the message:

    {“error”:{“type”:”Illuminate\Database\Eloquent\MassAssignmentException”,”message”:”text”,”file”:”/var/www/laravelangularjs/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php”,”line”:309}}

    In the comment model, you need:

    protected $fillable = array(‘author’, ‘text’);

    as per the docs at http://laravel.com/docs/eloquent#mass-assignment

    Apart from that, great tutorial.

    • http://scotch.io/ Chris Sevilleja

      Ah very good input. I was wondering why I was having problems with that sometimes. Thanks very much for the info and I’ll update the tutorial.

  • rt

    problem with your git repository.

    Cloning into ‘laravel-angular-comment-app’…

    Permission denied (publickey).

    fatal: Could not read from remote repository.

    Please make sure you have the correct access rights

    and the repository exists.

    • http://scotch.io/ Chris Sevilleja

      Maybe try cloning via HTTPS instead? That’s weird.

      https://github.com/scotch-io/laravel-angular-comment-app.git

      • rt

        it’s ok i grabbed the code from github download.

    • Erik

      *5 minutes ago while reading this comment, “This guy is having issues cloning this repo… Weird.”

      *Present:
      Cloning into ‘laravel-angular-comment-app’…
      Permission denied (publickey).
      fatal: Could not read from remote repository.

      “… Oh, I guess he wasn’t crazy.”

      • http://scotch.io/ Chris Sevilleja

        Try cloning this one: https://github.com/scotch-io/laravel-angular-comment-spa

        If that works, I’m going to change the repo for the tutorial. The only thing I can think of that was different than normal is that I renamed the repo right before I pushed the article live.

        • Erik

          I just swapped to HTTPS in favor of SSH and it came down fine.

          Now that I think about it.. Odd… since I forked it on Github and tried to clone my own repo via SSH, which I believe has been working fine otherwise. Hmmm that will have me thinking a bit.

          • http://scotch.io/ Chris Sevilleja

            Weird. Did cloning that new repo I made via SSH work?

          • Erik

            I can clone both via HTTPS but nothing (including my own repos) with SSH.

            Maybe I’ve got a problem locally. … maybe Github is broken. One or the other ;)

          • http://scotch.io/ Chris Sevilleja

            Let’s call it Github is broken. It’s more fun that way.

  • rt

    I haven’t tried it yet, but does angular routing conflict with laravel routing?

    • http://scotch.io/ Chris Sevilleja

      No the Angular routing doesn’t conflict with the Laravel routing. We use a catch-all route in Laravel to direct all requests to Angular. So Angular only routes the things that Laravel gives it.

  • jvoelkel

    Thanks for the tutorial, Chris.

    I must have made a mistake somewhere along the line – I’m getting an internal server error saying the author column cannot be null:

    {“error”:{“type”:”Illuminate\Database\QueryException”,”message”:”SQLSTATE[23000]: Integrity constraint violation: 1048 Column ‘author’ cannot be null (SQL: insert into `comments` (`author`, `text`, `updated_at`, `created_at`) values (, , 2014-02-05 18:31:53, 2014-02-05 18:31:53))”,”file”:”C:\wamp\www\angular\vendor\laravel\framework\src\Illuminate\Database\Connection.php”,”line”:539}}
    However, cloning the git repo worked just fine for me.

  • Erik

    Perfect jumping point for a project I will be starting on soon. Thank you for laying everything out so clearly and commenting each piece. Can’t wait to put it to use.

    • http://scotch.io/ Chris Sevilleja

      Sweet. Let me know if there are any major changes you’d like. I’m probably going to extend this and add frontend routing parts too.

      • Daniel Bethel

        Any idea when this expansion will take place?

        • http://scotch.io/ Chris Sevilleja

          I will try to get to it in the beginning of March. What are the main things you’d like to see?

          • Daniel Bethel

            Interested in seeing some frontend authentication with angular. Pulling credentials from the Laravel side and logging a user in without page refresh then maybe pulling in certain view elements only when a user is logged in

          • http://scotch.io/ Chris Sevilleja

            Gotcha. I’ve been getting a lot of requests for that. I’m going to create that as its own separate article. Also going to do Laravel authentication with Facebook, Twitter, and Google. I’ll definitely try to push those out this coming month.

            Thanks for the feedback.

          • Daniel Bethel

            Would be greatly appreciated. In the meantime I’ll play around and try to figure it out myself lol

  • Jeremy Swinborne

    I noticed a small typo. Where you say, “Create a file: app/database/seeds/DatabaseSeeder.php and fill it with this code.” I believe you mean app/database/seeds/CommentTableSeeder.php, since in the very next step we need to update the DatabaseSeeder.php file. Great tutorial though! Thank you!

    • http://scotch.io/ Chris Sevilleja

      You are absolutely right. Fixed. Thanks.

  • jvoelkel

    I’m just getting started with both Laravel and Angular and I was curious – if this were a multi-page application, would the routing be handled through Angular or Laravel or some combination of the two?

    It makes sense in my head to just have Laravel handle api calls only and leave the view routing to Angular but I’m not sure if that is correct or even makes sense to do.

    • http://scotch.io/ Chris Sevilleja

      The routing for the multiple pages would be handled through Angular. You would define all your Laravel routes (API stuff) and then you would create a catch-all route. With this route, if Laravel didn’t know where to route a request, it would send the request to the frontend index.php file. From there Angular would handle all the routing for the multiple pages.

      • jvoelkel

        Very cool! Thanks!

  • http://localhost:3000/ twlizard

    great tutorial so far! just one question, I used your code for the routes but when I check my routes from the command line I don’t have a row for api.comments.show. I wasn’t expecting to have that route since we didn’t create a show controller but you have that route available in your screenshot. Should there be a show controller? Is there something I’m missing?

  • http://localhost:3000/ twlizard

    Also I get this error when I try and seed the db:

    [PDOException]

    SQLSTATE[HY000] [1045] Access denied for user ‘root’@’

    localhost’ (using password: NO)

    • http://localhost:3000/ twlizard

      I fixed this. I’m new to MAMP so after a little poking around I saw the information I need was in the phpMyAdmin link.

  • Pingback: Quick Tip: Using Laravel Blade with AngularJS ♥ Scotch

  • gode

    Hey Thank You for this nice Tutorial. But it seems to me that the Angular part is somehow not working right.
    Get-> shows nothing, just the loading smiley. And hitting the Submit button-> no new post will be created.

    Thought my API is wrong but everything works fine using the blade.view/Postman. As i am new to Angular i can’t figure out the Problem.

    • gode

      problem solved, had to adjust the route in the commentService. ty

      • Eric Leroy

        Can you tell me the way you’ve changed it ? Because I think we’ve got the same issue ;-(

        • gode

          simply the “address” of the api. so in commentService.js instead of just:
          return $http.get(‘api/comments’); i “completed” the route to
          return $http.get(‘/baseFolder/public/api/comments’); . maybe you should also add a “/” to the beginning e.g. (/api/comments) not just (api/comments) .

          Also keep in mind to set the //protected $fillable = array (‘text’,’author’);// in the CommentModel class.
          Hope this helps

          • Guest

            facing same problem. As new in both Laravel and angular, I will very much appreciate if you can show the files I need to edit.

            “Its frustrating when even a copy paste work doesnt work”

          • Kar

            If you run “php artisan serve” the page works correctly. The page is not working on apache server. I have tried with MAMP an XAMPP.

          • Laramason

            facing same problem. Your solution doesnt work for me. As new in both Laravel and angular, I will very much appreciate if you can show the files I need to edit.

            “Its very frustrating when even a copy paste work doesnt work”

  • Eric Leroy

    Great tutorial but I always get the same issue :

    GET http://localhost:8888/api/comments 404 (Not Found)

    Unable to view existing comments. The same when trying to save a comment…
    Any idea ?

    • http://scotch.io/ Chris Sevilleja

      From your command line, when you type php artisan routes what routes do you see?

      • Eric Leroy

        The same as you :

        +——–+——————————–+———————-+—————————+—————-+—————+

        | Domain | URI | Name | Action | Before Filters | After Filters |

        +——–+——————————–+———————-+—————————+—————-+—————+

        | | GET / | | Closure | | |

        | | GET api/comments | api.comments.index | CommentController@index | | |

        | | POST api/comments | api.comments.store | CommentController@store | | |

        | | GET api/comments/{comments} | api.comments.show | CommentController@show | | |

        | | DELETE api/comments/{comments} | api.comments.destroy | CommentController@destroy | | |

        +——–+——————————–+———————-+—————————+—————-+—————+

        • http://scotch.io/ Chris Sevilleja

          When you do Comment.get(), add an error in there so you can see if an error comes back in the console.

          Comment.get()
          .success(function(data) {
          $scope.comments = data;
          $scope.loading = false;
          })
          .error(function(data) {
          console.log(data);
          });

          Also, can you go to the route directly in the browser? http://localhost:8888/myapp/public

          • Eric Leroy

            Trapping error : nothing in the console.
            With :
            http://localhost:8888/larang/public/api/comments
            I get the json :

            [{"id":"1","text":"Look I am a test comment.","author":"Chris Sevilleja","created_at":"2014-02-12 22:40:17","updated_at":"2014-02-12 22:40:17"},{"id":"2","text":"This is going to be super crazy.","author":"Nick Cerminara","created_at":"2014-02-12 22:40:17","updated_at":"2014-02-12 22:40:17"},{"id":"3","text":"I am a master of Laravel and Angular.","author":"Holly Lloyd","created_at":"2014-02-12 22:40:17","updated_at":"2014-02-12 22:40:17"}]

            It is as if CommentService.js was not called or did not call routes.php

          • http://scotch.io/ Chris Sevilleja

            If that is the URL you see data at, then use that URL in your CommentService. Since there are no console errors then there aren’t any errors loading up the CommentService.

            Try using the /larang/public/api/comments as the URL.

          • Eric Leroy

            I already tried that. It sounds so simple ;-). But unfortunatly the answer is :

            Error: [ngRepeat:dupes] http://errors.angularjs.org/1.2.8/ngRepeat/dupes?p0=comment%20in%20comments&p1=string%3At

            When i try

            http://localhost:8888/larang/public/foo/bar (catching all route) -> see image and I get the error :

            Resource interpreted as Script but transferred with MIME type text/html: “http://localhost:8888/larang/public/foo/js/app.js”. bar:24

            Resource interpreted as Script but transferred with MIME type text/html: “http://localhost:8888/larang/public/foo/js/controllers/mainCtrl.js”. bar:22

            Resource interpreted as Script but transferred with MIME type text/html: “http://localhost:8888/larang/public/foo/js/services/commentService.js”. bar:23

            Uncaught SyntaxError: Unexpected token < mainCtrl.js:1

            Uncaught SyntaxError: Unexpected token < commentService.js:1

            Uncaught SyntaxError: Unexpected token < app.js:1

            Uncaught Error: [$injector:modulerr] http://errors.angularjs.org/1.2.8/$injector/modulerr?p0=commentApp&p1=Error…ogleapis.com%2Fajax%2Flibs%2Fangularjs%2F1.2.8%2Fangular.min.js%3A17%3A431)

            Uncaught SyntaxError: Unexpected token < mainCtrl.js:1

            Uncaught SyntaxError: Unexpected token < commentService.js:1

            Uncaught SyntaxError: Unexpected token < app.js:1

            Uncaught Error: [$injector:modulerr] http://errors.angularjs.org/1.2.8/$injector/modulerr?p0=commentApp&p1=Error…ogleapis.com%2Fajax%2Flibs%2Fangularjs%2F1.2.8%2Fangular.min.js%3A17%3A431)

          • gode

            i had the same errors. check if your db table is named correct, if it is not ‘comments’ then add a //protected $table = ‘myTableName’;// on top of your commentModel. (laravel will only look for a table with the name of the model).
            Look at my post below for more “ideas” on how to solve the problem.

          • Daniel Bethel

            Try removing the slash and just putting api/comments instead of /api/comments when declaring your route and getting the http request. strangely enough that seems to work for me.

          • mandofever

            Wondering if the OP ever got his issues sorted? Having the same problem, unfortunately none of the solutions here (or below) have helped me.

          • mandofever

            Just figured it out! i had this error msg much like the OP’s http://docs.angularjs.org/error/ngRepeat/dupes?p0=comment%20in%20comments&p1=string:%2F

            It claimed that a duplicate of “string: /” was causing the error. After looking at the raw JSON being returned at /myApp/public/api/comments I noticed that the first two characters returned were the beginning slashes from this line (// app/models/Comment.php) commenting out the first line of app/models/Comment.php

            After removing the offending comment in Comment.php and adjusting the URLs in CommentService.js everything worked properly!

          • جنید احمد

            for me it is saving comments now , but not showing it so what to do?
            i have removed the /api/comment —-> api/comment

          • جنید احمد

            Please ans me . it is saving comments in Table, but not showing

          • جنید احمد

            ng-repeat=”comment in comments”

            am getting error of Ng-Repeat Dupes

  • Martin Litvaj

    Hi, thanks for great tutorial. I am new to laravel and I have a problem with URL. Maybe it is trivial, but app does not load comments. In firebug it says GET http://localhost/api/comments 404 not found. I have to edit commentService.js and change return $http.get(‘/api/comments’); to return $http.get(‘/ms-project/public/api/comments’); . What am I doing wrong? Thanks

    • gode

      maybe you should hit the http://localhost/ms-project/public/api/comments/ ?…sorry if this didn’t help

    • asif

      I just solved the problem by replacing “/api/comments” with “/my_project_name/public/api/comments” in the commentService.js file. Hope this helps.

  • waseemmachloy

    what is benefit for using angular,js in this comment system. :) just curious about angula.js benefit

    • http://scotch.io/ Chris Sevilleja

      This example doesn’t fully show the power that Angular can provide in this setup. Handling the AJAX calls in an Angular service and having separated code out into controllers lets us expand our app easier than if we were creating this with just jQuery.

      Since the service and controller are separate and modular, we can run unit tests on our app to make sure that everything works according to plan. While this doesn’t show too much of the benefits, when you want to build a larger application, it can help greatly for testability, scalability of code, and handling the front-end data is so much easier.

  • Pingback: Дайджест интересных новостей и материалов из мира PHP № 36 (9 — 23 февраля 2014) | Вести3.ру — Информационный журнал

  • Pingback: Дайджест интересных новостей и материалов из мира PHP № 36 (9 — 23 февраля 2014) » CreativLabs

  • Pingback: Laravel and AngularJS: Ignite Your App Development -JustinVoelkel.me

  • Alex

    Thanks for that nice little tutorial. It all worked straight away ( very rare with me ) and i am now inspired to continue digging in that direction. Cheers and keep up the good work.

  • http://hkajax.wordpress.com/ Hemant Singh

    Just awesome tutorial this is what I was looking for, very nice
    separation of concern (front end and back end) one very tiny question –
    is their any way we can rename index.php to index.html that can be
    referenced from laravel route something like this…

    Route::get(‘/’, function()
    {
    return View::make(‘index.html’); // or index
    });

    • http://scotch.io/ Chris Sevilleja

      I am not entirely sure if you can just use index.html. If you don’t want to use Blade, just use an index.php file. Then you can do return View::make('index'); and it will act just like an HTML file without Blade.

      • http://hkajax.wordpress.com/ Hemant Singh

        my main idea was to open file directly in browser, even designers love to work with html layout it’s bit difficult for then to maintain .php down the road.
        love you dear Chris for very quick reply, bunch of thanks!

        • http://scotch.io/ Chris Sevilleja

          Gotcha. Even though it is named a PHP file, you don’t have to use PHP in it at all.

  • David Knight

    On submit and destroy success, you don’t need to refresh the comment list using .get(), you should simply $scope.comments.push( $scope.commentData ) and $scope.comments.splice( index, 1 ) where index is passed into the destroy function as a parameter. This would save you two additional XHR requests and unnecessary wait and load time.

  • Tim

    >Getting our Database Ready
    >php artisan migrate:make create_comments_table –create=comments

    Could you fix this to
    php artisan migrate:make create_comments_table –table=comments –create

    As on the screen beside
    Thanks!

  • waseemmachloy
  • waseemmachloy

    Also can you do can kind of tutorial on real time webapp with laravel , for example to make this comment system real time, if 1st user comment on same system then any notification can show on to 2nd user that new comment is added etc. i see this site https://www.meteor.com/ and it looks good.

  • http://alec.is Alec Ritson

    This was really helpful, thanks! Everything worked first time without any issues