One place for hosting & domains

      Create

      Create a MEAN app with Angular and Docker Compose

      Introduction

      Note: Update: 30/03/2019

      This article has been updated based on the updates to both docker and angular since this article was written. The current version of angular is 7, the updates also adds an attached docker volume to the angular client so that you don’t need to run docker-compose build every time.

      Docker allows us to run applications inside containers. These containers in most cases communicate with each other.

      Docker containers wrap a piece of software in a complete filesystem that contains everything needed to run: code, runtime, system tools, system libraries – anything that can be installed on a server. This guarantees that the software will always run the same, regardless of its environment.

      We’ll build an angular app in one container, point it to an Express API in another container, which connects to MongoDB in another container.

      If you haven’t worked with Docker before, this would be a good starting point as we will explain every step covered, in some detail.

      Why Use Docker

      1. Docker images usually include only what your application needs to run. As a result, you don’t have to worry about having a whole operating system with things you will never use. This results in smaller images of your application.
      2. Platform Independent – I bet you’ve heard of the phrase ‘It worked on my machine and doesn’t work on the server’. With Docker, all either environments need to have is the Docker Engine or the Docker Daemon, and when we have a successful build of our image, it should run anywhere.
      3. Once you have an image of your application built, you can easily share the image with anyone who wants to run your application. They need not worry about dependencies, or setting up their individual environments. All they need to have is Docker Engine installed.
      4. Isolation – You’ll see from the article that I try to separate the individual apps to become independent, and only point to each other. The reason behind this is that each part of our entire application should be somewhat independent, and scalable on its own. Docker in this instance would make scaling these individual parts as easy as spinning up another instance of their images. This concept of building isolated, independently scalable parts of an entire system are what is called Microservices Approach. You can read more about it in Introduction to Microservices
      5. Docker images usually have tags, referring to their versions. This means you can have versioned builds of your image, enabling you to roll back to a previous version should something unexpected break.

      You need to have docker and docker-compose installed in your setup. Instructions for installing docker in your given platform can be found here.

      Instructions for installing docker-compose can be found here.

      Verify your installation by running:

      1. docker -v

      Output

      Docker version 18.09.2, build 6247962
      1. docker-compose -v

      Output

      docker-compose version 1.23.2, build 1110ad01
      1. node -v

      Output

      v11.12.0

      Next, you need to know how to build a simple Angular app and an Express App. We’ll be using the Angular CLI to build a simple app.

      We’ll now separately build out these three parts of our app. The approach we are going to take is building the app in our local environment, then dockerizing the app.

      Once these are running, we’ll connect the three docker containers. Note that we are only building two containers, Angular and the Express/Node API. The third container will be from a MongoDB image that we’ll just pull from the Docker Hub.

      Docker Hub is a repository for docker images. It’s where we pull down official docker images such as MongoDB, NodeJs, Ubuntu, and we can also create custom images and push them to Docker Hub for other people to pull and use.

      Let’s create a directory for our whole setup, we’ll call it mean-docker.

      1. mkdir mean-docker

      Next, we’ll create an Angular app and make sure it runs in a docker container.

      Create a directory called angular-client inside the mean-docker directory we created above, and initialize an Angular App with the Angular CLI.

      We’ll use npx, a tool that allows us to run CLI apps without installing them into our system. It comes preinstalled when you install Node.js since version 5.2.0

      1. npx @angular/cli new angular-client
      ? Would you like to add Angular routing? No
      ? Which stylesheet format would you like to use? CSS
      

      This scaffolds an Angular app, and npm installs the app’s dependencies. Our directory structure should be like this

      └── mean-docker
          └── angular-client
              ├── README.md
              ├── angular.json
              ├── e2e
              ├── node_modules
              ├── package.json
              ├── package-lock.json
              ├── src
              ├── tsconfig.json
              └── tslint.json
      

      Running npm start, inside the angular-client directory should start the angular app at http://localhost:4200.

      To dockerize any app, we usually need to write a Dockerfile

      A Dockerfile is a text document that contains all the commands a user could call on the command line to assemble an image.

      To quickly brainstorm on what our angular app needs in order to run,

      1. We need an image with Node.js installed on it
      2. We could have the Angular CLI installed on the image, but the package.json file has it as a dependency, so it’s not a requirement.
      3. We can add our Angular app to the image and install its dependencies.
      4. It needs to expose port 4200 so that we can access it from our host machine through localhost:4200.
      5. If all these requirements are met, we can run npm start in the container, which in turn runs ng serve since it’s a script in the package.json file, created from the image and our app should run.

      Those are the exact instructions we are going to write in our Dockerfile.

      mean-docker/angular-client/Dockerfile

      # Create image based on the official Node 10 image from dockerhub
      FROM node:10
      
      # Create a directory where our app will be placed
      RUN mkdir -p /app
      
      # Change directory so that our commands run inside this new directory
      WORKDIR /app
      
      # Copy dependency definitions
      COPY package*.json /app/
      
      # Install dependencies
      RUN npm install
      
      # Get all the code needed to run the app
      COPY . /app/
      
      # Expose the port the app runs in
      EXPOSE 4200
      
      # Serve the app
      CMD ["npm", "start"]
      

      I’ve commented on the file to show what each instruction clearly does.

      Note: Before we build the image, if you are keen, you may have noticed that the line COPY . /app/ copies our whole directory into the container, including node_modules. To ignore this, and other files that are irrelevant to our container, we can add a .dockerignore file and list what is to be ignored. This file is usually sometimes identical to the .gitignore file.

      Create a .dockerignore file.

      mean-docker/angular-client/.dockerignore

      node_modules/
      

      One last thing we have to do before building the image is to ensure that the app is served from the host created by the docker image. To ensure this, go into your package.json and change the start script to:

      mean-docker/angular-client/package.json

      {
       ...
        "scripts": {
          "start": "ng serve --host 0.0.0.0",
          ...
        },
        ...
      }
      

      To build the image we will use docker build command. The syntax is

      1. docker build -t <image_tag>:<tag> <directory_with_Dockerfile>

      Make sure you are in the mean_docker/angular-client directory, then build your image.

      1. cd angular-client
      1. docker build -t angular-client:dev .

      -t is a shortform of --tag, and refers to the name or tag given to the image to be built. In this case the tag will be angular-client:dev.

      The . (dot) at the end refers to the current directory. Docker will look for the Dockerfile in our current directory and use it to build an image.

      This could take a while depending on your internet connection.

      Now that the image is built, we can run a container based on that image, using this syntax

      1. docker run -d --name <container_name> -p <host-port:exposed-port> <image-name>

      The -d flag tells docker to run the container in detached mode. Meaning, it will run and get you back to your host, without going into the container.

      1. docker run -d --name angular-client -p 4200:4200 angular-client:dev 8310253fe80373627b2c274c5a9de930dc7559b3dc8eef4abe4cb09aa1828a22

      --name refers to the name that will be assigned to the container.

      -p or --port refers to which port our host machine should point to in the docker container. In this case, localhost:4200 should point to dockerhost:4200, and thus the syntax 4200:4200.

      Visit localhost:4200 in your host browser should be serving the angular app from the container.

      You can stop the container running with:

      1. docker stop angular-client

      We’ve containerized the angular app, we are now two steps away from our complete setup.

      Containerizing an express app should now be straightforward. Create a directory in the mean-docker directory called express-server.

      1. mkdir express-server

      Add the following package.json file inside the app.

      mean-docker/express-server/package.json

      {
        "name": "express-server",
        "version": "0.0.0",
        "private": true,
        "scripts": {
          "start": "node server.js"
        },
        "dependencies": {
          "body-parser": "~1.15.2",
          "express": "~4.14.0"
        }
      }
      

      Then, we’ll create a simple express app inside it. Create a file server.js

      1. cd express-serve
      1. touch server.js
      1. mkdir routes && cd routes
      1. touch api.js

      mean-docker/express-server/server.js

      
      const express = require('express');
      const path = require('path');
      const http = require('http');
      const bodyParser = require('body-parser');
      
      
      const api = require('./routes/api');
      
      const app = express();
      
      
      app.use(bodyParser.json());
      app.use(bodyParser.urlencoded({ extended: false }));
      
      
      app.use('/', api);
      
      
      const port = process.env.PORT || '3000';
      app.set('port', port);
      
      
      const server = http.createServer(app);
      
      
      server.listen(port, () => console.log(`API running on localhost:${port}`));
      
      [labe mean-docker/express-server/routes/api.js]
      const express = require('express');
      const router = express.Router();
      
      
      router.get('/', (req, res) => {
          res.send('api works');
      });
      
      module.exports = router;
      

      This is a simple express app, install the dependencies and start the app.

      1. npm install
      1. npm start

      Going to localhost:3000 in your browser should serve the app.

      To run this app inside a Docker container, we’ll also create a Dockerfile for it. It should be pretty similar to what we already have for the angular-client.

      mean-docker/express-server/Dockerfile

      # Create image based on the official Node 6 image from the dockerhub
      FROM node:6
      
      # Create a directory where our app will be placed
      RUN mkdir -p /usr/src/app
      
      # Change directory so that our commands run inside this new directory
      WORKDIR /usr/src/app
      
      # Copy dependency definitions
      COPY package.json /usr/src/app
      
      # Install dependencies
      RUN npm install
      
      # Get all the code needed to run the app
      COPY . /usr/src/app
      
      # Expose the port the app runs in
      EXPOSE 3000
      
      # Serve the app
      CMD ["npm", "start"]
      

      You can see the file is pretty much the same as the angular-client Dockerfile, except for the exposed port.

      You could also add a .dockerignore file to ignore files we do not need.

      mean-docker/express-server/.dockerignore

      node_modules/
      

      We can then build the image and run a container based on the image with:

      1. docker build -t express-server:dev .
      1. docker run -d --name express-server -p 3000:3000 express-server:dev

      Going to localhost:3000 in your browser should serve the API.

      Once you are done, you can stop the container with

      1. docker stop express-server

      The last part of our MEAN setup, before we connect them all together is the MongoDB. Now, we can’t have a Dockerfile to build a MongoDB image, because one already exists from the Docker Hub. We only need to know how to run it.

      Assuming we had a MongoDB image already, we’d run a container based on the image with

      1. docker run -d --name mongodb -p 27017:27017 mongo

      The image name in this instance is mongo, the last parameter, and the container name will be mongodb.

      Docker will check to see if you have a mongo image already downloaded, or built. If not, it will look for the image in the Dockerhub. If you run the above command, you should have a mongodb instance running inside a container.

      To check if MongoDB is running, simply go to http://localhost:27017 in your browser, and you should see this message. It looks like you are trying to access MongoDB over HTTP on the native driver port.

      Alternatively, if you have mongo installed in your host machine, simply run mongo in the terminal. And it should run and give you the mongo shell, without any errors.

      To connect and run multiple containers with docker, we use Docker Compose.

      Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a Compose file to configure your application’s services. Then, using a single command, you create and start all the services from your configuration.

      docker-compose is usually installed when you install docker. So to simply check if you have it installed, run:

      1. docker-compose

      You should see a list of commands from docker-compose. If not, you can go through the installation here

      Note: Ensure that you have docker-compose version 1.6 and above by running docker-compose -v

      Create a docker-compose.yml file at the root of our setup.

      1. touch docker-compose.yml

      Our directory tree should now look like this.

      .
      ├── angular-client
      ├── docker-compose.yml
      └── express-server
      

      Then edit the docker-compose.yml file

      mean-docker/docker-compose.yml

      version: '2' 
      
      
      services:
        angular: 
          build: angular-client 
          ports:
            - "4200:4200" 
      
        express: 
          build: express-server 
          ports:
            - "3000:3000" 
      
        database: 
          image: mongo 
          ports:
            - "27017:27017" 
      

      The docker-compose.yml file is a simple configuration file telling docker-compose which containers to build. That’s pretty much it.

      Now, to run containers based on the three images, simply run

      1. docker-compose up

      This will build the images if not already built, and run them. Once it’s running, and your terminal looks something like this.

      You can visit all three apps: http://localhost:4200, http://localhost:3000, or mongodb://localhost:27017. And you’ll see that all three containers are running.

      Finally, the fun part.

      Express and MongoDB

      We now finally need to connect the three containers. We’ll first create a simple CRUD feature in our API using mongoose. You can go through Easily Develop Node.js and MongoDB Apps with Mongoose to get a more detailed explanation of mongoose.

      First of all, add mongoose to your express server package.json

      mean-docker/express-server/package.json

      {
        "name": "express-server",
        "version": "0.0.0",
        "private": true,
        "scripts": {
          "start": "node server.js"
        },
        "dependencies": {
          "body-parser": "~1.15.2",
          "express": "~4.14.0",
          "mongoose": "^4.7.0"
        }
      }
      

      We need to update our API to use MongoDB:

      mean-docker/express-server/routes/api.js

      
      const mongoose = require('mongoose');
      const express = require('express');
      const router = express.Router();
      
      
      const dbHost = 'mongodb://database/mean-docker';
      
      
      mongoose.connect(dbHost);
      
      
      const userSchema = new mongoose.Schema({
        name: String,
        age: Number
      });
      
      
      const User = mongoose.model('User', userSchema);
      
      
      
      router.get('/', (req, res) => {
              res.send('api works');
      });
      
      
      router.get('/users', (req, res) => {
          User.find({}, (err, users) => {
              if (err) res.status(500).send(error)
      
              res.status(200).json(users);
          });
      });
      
      
      router.get('/users/:id', (req, res) => {
          User.findById(req.param.id, (err, users) => {
              if (err) res.status(500).send(error)
      
              res.status(200).json(users);
          });
      });
      
      
      router.post('/users', (req, res) => {
          let user = new User({
              name: req.body.name,
              age: req.body.age
          });
      
          user.save(error => {
              if (error) res.status(500).send(error);
      
              res.status(201).json({
                  message: 'User created successfully'
              });
          });
      });
      
      module.exports = router;
      

      Two main differences, first of all, our connection to MongoDB is in the line const dbHost="mongodb://database/mean-docker";. This database is the same as the database service we created in the docker-compose file.

      We’ve also added rest routes GET /users, GET /users/:id and POST /user.

      Update the docker-compose file, telling the express service to link to the database service.

      mean-docker/docker-compose.yml

      version: '2' 
      
      
      services:
        angular: 
          build: angular-client 
          ports:
            - "4200:4200" 
          volumes:
            - ./angular-client:/app 
      
        express: 
          build: express-server 
          ports:
            - "3000:3000" 
          links:
            - database
      
        database: 
          image: mongo 
          ports:
            - "27017:27017" 
      

      The links property of the docker-compose file creates a connection to the other service with the name of the service as the hostname. In this case database will be the hostname. Meaning, to connect to it from the express service, we should use database:27017. That’s why we made the dbHost equal to mongodb://database/mean-docker.

      Also, I’ve added a volume to the angular service. This will enable changes we make to the Angular App to automatically trigger recompilation in the container

      Angular and Express

      The last part is to connect the Angular app to the express server. To do this, we’ll need to make some modifications to our angular app to consume the express API.

      Add the Angular HTTP Client.

      mean-docker/angular-client/src/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 { }
      

      mean-docker/angular-client/src/app/app.component.ts

      import { Component, OnInit } from '@angular/core';
      import { HttpClient } from '@angular/common/http';
      
      @Component({
        selector: 'app-root',
        templateUrl: './app.component.html',
        styleUrls: ['./app.component.css']
      })
      export class AppComponent implements OnInit {
        title = 'app works!';
      
        
        API = 'http://localhost:3000';
      
        
        people: any[] = [];
      
        constructor(private http: HttpClient) {}
      
        
        ngOnInit() {
          this.getAllPeople();
        }
      
        
        addPerson(name, age) {
          this.http.post(`${this.API}/users`, {name, age})
            .subscribe(() => {
              this.getAllPeople();
            })
        }
      
        
        getAllPeople() {
          this.http.get(`${this.API}/users`)
            .subscribe((people: any) => {
              console.log(people)
              this.people = people
            })
        }
      }
      

      Angular best practices guides usually recommend separating most logic into a service/provider. We’ve placed all the code in the component here for brevity.

      We’ve imported the OnInit interface, to call events when the component is initialized, then added two methods AddPerson and getAllPeople, that call the API.

      Notice that this time around, our API is pointing to localhost. This is because while the Angular 2 app will be running inside the container, it’s served to the browser. And the browser is the one that makes requests. It will thus make a request to the exposed Express API. As a result, we don’t need to link Angular and Express in the docker-compose.yml file.

      Next, we need to make some changes to the template. I first added bootstrap via CDN to the index.html

      mean-docker/angular-client/src/app/index.html

      <!doctype html>
      <html>
      <head>
        <meta charset="utf-8">
        <title>Angular Client</title>
        <base href="/">
      
        <meta name="viewport" content="width=device-width, initial-scale=1">
      
        
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.2/css/bootstrap.min.css">
      
        <link rel="icon" type="image/x-icon" href="favicon.ico">
      </head>
      <body>
        <app-root>Loading...</app-root>
      </body>
      </html>
      

      Then update the app.component.html template

      mean-docker/angular-client/src/app/app.component.html

      
      <nav class="navbar navbar-light bg-faded">
        <div class="container">
          <a class="navbar-brand" href="#">Mean Docker</a>
        </div>
      </nav>
      
      <div class="container">
          <h3>Add new person</h3>
          <form>
            <div class="form-group">
              <label for="name">Name</label>
              <input type="text" class="form-control" id="name" #name>
            </div>
            <div class="form-group">
              <label for="age">Age</label>
              <input type="number" class="form-control" id="age" #age>
            </div>
            <button type="button" (click)="addPerson(name.value, age.value)" class="btn btn-primary">Add person</button>
          </form>
      
          <h3>People</h3>
          
          <div class="card card-block col-md-3" *ngFor="let person of people">
            <h4 class="card-title">{{person.name}}  {{person.age}}</h4>
          </div>
      </div>
      

      The above template shows the components’ properties and bindings. We are almost done.

      Since we’ve made changes to our code, we need to do a build for our Docker Compose

      1. docker-compose up --build

      The --build flag tells docker compose that we’ve made changes and it needs to do a clean build of our images.

      Once this is done, go to localhost:4200 in your browser,

      We are getting a No 'Access-Control-Allow-Origin' error. To quickly fix this, we need to enable Cross-Origin in our express app. We’ll do this with a simple middleware.

      mean-docker/express-server/server.js

      
      
      
      app.use(bodyParser.json());
      app.use(bodyParser.urlencoded({ extended: false }));
      
      
      app.use(function(req, res, next) {
        res.header("Access-Control-Allow-Origin", "*")
        res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept")
        next()
      })
      
      
      app.use('/', api);
      
      
      

      We can now run docker-compose again with the build flag. You should be in the mean-docker directory.

      1. docker-compose up --build

      Going to localhost:4200 on the browser.

      Note: I added an attached volume to the docker-compose file, and we now no longer need to rebuild the service every time we make a change.

      I bet you’ve learned a thing or two about MEAN or docker and docker-compose.

      The problem with our set up however is that any time we make changes to either the angular app or the express API, we need to run docker-compose up --build.

      This can get tedious or even boring over time. We’ll look at this in another article.

      Debugging Create React App Applications in Visual Studio Code

      Introduction

      In this post, we are going to create a Create React App application, then add configuration to debug it in Visual Studio Code.

      For a Create React App application, install the Debugger for Chrome extension, create a debug configuration in VS Code, and then run in debug mode.

      To be able to test a Create React App application, you will need a Create React App application. I’ll provide the basic steps, but for more reference on how to get started look at the Create React App page.

      First, you’ll need to install the Create React App.

      1. npm install -g create-react-app

      After that finishes, you’ll need to actually generate your new application. This will take a bit as it needs to install lots of npm packages.

      1. create-react-app my-app

      Open the project in VS Code and you should see the following.

      Create React App Project in VS Code

      Now, that you’ve got your new fancy React app, go ahead and run it to make sure everything looks right.

      1. npm start

      Should look like this.

      Create React App Project Running

      Assuming you’ve made it this far, we are ready to start debugging! Before we do, however, it’s worth understanding how configuring debugging in VS Code works. Basically, debug configurations are saved in a launch.json file which is stored inside of a .vscode folder. This .vscode folder is used to store different configurations for Code including our required debugging stuff.

      Before you create your debug configuration, you need to install the Debugger for Chrome extension. Find and install this extension from the extension tab in VS Code. After installing, reload VS Code.

      Debugger for Chrome

      Now, to create a debug configuration, you can open the debug panel (the bug-looking button on the left panel). At the top of the debug panel, you should see a dropdown that says “No Configurations”.

      Create Debug Configurations

      To the right of that dropdown, there is a gear icon. Click this button to have VS Code automatically generate that .vscode folder and launch.json file mentioned above.

      Then choose Chrome.

      Choose Chrome Debug Configuration

      You should get the following configuration created for you.

      Create React App Debug Configuration

      The only thing we need to do is update the port from 8080 to 3000.

      Updated Create React App Debug Configuration

      Now we’re ready! Go ahead and click the play button at the top of the Debug panel which will launch an instance of Chrome in debug mode. Keep in mind your app should already be running from using ng serve earlier. In VS Code, you should see the Debug toolbar pop up.

      With this up and running, you can set a breakpoint in your App.js. Open up your App.js and add a breakpoint inside of the render function by clicking in the gutter (to the left of the line numbers). Should look like this.

      Now, refresh debugging by clicking the refresh button on the debugging toolbar. This should open your application again and trigger this breakpoint. You should be directed back to VS Code directly to the place where you set your breakpoint.

      From here, you can set more breakpoints, inspect variables, etc. If you are interested in learning more about debugging JavaScript in general in either Chrome or VS Code you can check out Debugging JavaScript in Chrome and Visual Studio Code.

      If you have any follow-up questions or comments, leave one below or find me on Twitter @jamesqquick.

      For video content, check out my YouTube Channel

      Create a Laravel and Angular Single Page Comment Application

      Introduction

      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.

      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 without page refresh
      • Ability to delete a comment and see it removed from our list without page refresh

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

      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:

      1. 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

          ...
      
              
              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:

      1. php artisan migrate

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

      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.

      app/models/Comment.php

          <?php
      
          class Comment extends Eloquent { 
      

      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.

      app/database/seeds/CommentTableSeeder.php

          <?php
      
          class CommentTableSeeder extends Seeder {
      
              public function run()
              {
                  DB::table('comments')->delete();
      
                  Comment::create(array(
                      'author' => 'Chris Sevilleja',
                      'text' => 'Comment by Chris.'
                  ));
      
                  Comment::create(array(
                      'author' => 'Nick Cerminara',
                      'text' => 'Comment by Nick.'
                  ));
      
                  Comment::create(array(
                      'author' => 'Holly Lloyd',
                      'text' => 'Comment by Holly.'
                  ));
              }
      
          }
      

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

      app/database/seeds/DatabaseSeeder.php

          ...
      
              
              public function run()
              {
                  Eloquent::unguard();
      
                  $this->call('CommentTableSeeder');
                  $this->command->info('Comment table seeded.');
              }
      
          ...
      

      Now let’s run our seeders using artisan.

      1. php artisan db: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.

      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.

      1. 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.

      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.

      app/controllers/CommentController.php

          <?php
      
          class CommentController extends BaseController {
      
              
              public function index()
              {
                  return Response::json(Comment::get());
              }
      
              
              public function store()
              {
                  Comment::create(array(
                      'author' => Input::get('author'),
                      'text' => Input::get('text')
                  ));
      
                  return Response::json(array('success' => true));
              }
      
              
              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.

      app/routes.php

          <?php
          
          
          
          
          Route::get('/', function() {
              View::make('index'); 
          });
      
          
          Route::group(array('prefix' => 'api'), function() {
      
              
              
              
              Route::resource('comments', 'CommentController',
                  array('only' => array('index', 'store', 'destroy')));
      
          });
      
          
          
          
          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:

      1. php artisan routes

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

      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 gets 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 on to the frontend Angular work.

      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 Using Laravel Blade with AngularJS. 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

          ...
      
              
              '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.

      Getting Our Application Ready

      Everything for our Angular application will be handled in the public folder. This lets 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 practice. 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
      

      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 : function() {
                      return $http.get('/api/comments');
                  },
      
                  
                  save : function(commentData) {
                      return $http({
                          method: 'POST',
                          url: '/api/comments',
                          headers: { 'Content-Type' : 'application/x-www-form-urlencoded' },
                          data: $.param(commentData)
                      });
                  },
      
                  
                  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', [])
      
          
          .controller('mainController', function($scope, $http, Comment) {
              
              $scope.commentData = {};
      
              
              $scope.loading = true;
      
              
              
              
              Comment.get()
                  .success(function(data) {
                      $scope.comments = data;
                      $scope.loading = false;
                  });
      
              
              
              $scope.submitComment = function() {
                  $scope.loading = true;
      
                  
                  
                  Comment.save($scope.commentData)
                      .success(function(data) {
      
                          
                          Comment.get()
                              .success(function(getData) {
                                  $scope.comments = getData;
                                  $scope.loading = false;
                              });
      
                      })
                      .error(function(data) {
                          console.log(data);
                      });
              };
      
              
              
              $scope.deleteComment = function(id) {
                  $scope.loading = true;
      
                  
                  Comment.destroy(id)
                      .success(function(data) {
      
                          
                          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 a best practice 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 
                  <p>{{ comment.text }}</p>
      
                  <p><a href="#" ng-click="deleteComment(comment.id)" class="text-muted">Delete</a></p>
              </div>
      
          </div>
          </body>
          </html>
      

      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.

      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!

      Hopefully, this tutorial gives a good overview of how to start an application using Laravel and Angular. You can bring this further 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.