Set up your AngularJS 1.x app module, routing and controllers - ultimagriever/mean-apz GitHub Wiki

It seems to me that I've created just a static web page. What now?

For starters, let's remove that h1 tag and its contents from our ng-view. That tag should have no content at all. Instead, we're going to inject components into it.

The app.js file

This will be the sole exception to what I will call the Gulp rule: this JavaScript code will be separated from the files that will be concatenated and, for that reason, will be included separately in our index.html. This is because the app.js will contain code written by you, the application developer, not third parties. It should make the application more maintainable and codeable than if we had to gulp for every single alteration, or if we had to keep a gulp watch task running at all times and concatenating everything all over again. Not saying it's useless, but its use is more recommended when we have lots of files to include and maintain, which is far away from being our case.

cd public/js
vi app.js

In the first line, I'll configure my AngularJS module as described below:

angular.module("employeesApp", ['ngRoute'])

where ngRoute is a dependency to my employeesApp app. Note that I'm using here the same name as I used in the ng-app directive in index.html. This is the core of our front-end logic, where all configuration (including routes), AngularJS controllers and custom directives will be declared and implemented.

For starters, let's configure our routes.

angular.module("employeesApp", ['ngRoute'])
  .config(function($routeProvider) {
    $routeProvider
    .when("/", {
      templateUrl: "list.html",
      controller: "ListController",
      resolve: {
        employees: function(Employees) {
          return Employees.getEmployees();
        }
      }
    })
    .when("/new/employees", {
      controller: "NewEmployeeController",
      templateUrl: "employee-form.html"
    })
    .when("/employees/:employeeId", {
      controller: "ViewEmployeeController",
      templateUrl: "employee.html"
    })
    .when("/edit/employees/:employeeId", {
      controller: "EditEmployeeController",
      templateUrl: "employee-form.html"
    })
    .otherwise({
      redirectTo: "/"
    });
  })

These routes indicate which template should be injected into index.html's ng-view container. This means we'll have a list.html file, an employee.html file and an employee-form.html file.

Let's have them all created.

list.html

vi list.html

<div class="row">
    <div class="col-md-6">
        <h2>Employees</h2>
    </div>
</div>
                                                
<div class="container">
    <table class="table table-hover table-responsive">
        <thead>
            <tr>
                <th>Name</th>
                <th>Age</th>
                <th>Job</th>
                <th colspan="3" style="text-align: center">
                    <a style="margin-top: 20px;" href="#/new/employees" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> Criar Novo</a>
                </th>
            </tr>
        </thead>
        <tbody>
            <tr ng-repeat="employee in employees">
                <td>
                    {{ employee.name }}
                </td>
                <td>
                    {{ employee.age }}
                </td>
                <td>
                    {{ employee.job }}
                </td>
                <td>
                    <a ng-href="#/employees/{{employee._id}}"><span class="glyphicon glyphicon-search"></span></a>
                </td>
                <td>
                    <a ng-href="#/edit/employees/{{employee._id}}"><span class="glyphicon glyphicon-edit"></span></a>
                </td>
                <td>
                    <a href="#/" ng-click="deleteEmployee(employee._id)"><span class="glyphicon glyphicon-delete"></span></a>
                </td>
            </tr>
        </tbody>
    </table>
</div>

employees.html

vi employees.html

<div class="row">
    <div class="col-md-6">
        <h2>{{ employee.name }}</h2>
    </div>
    <div class="col-md-3">
    </div>
    <div class="col-md-2">
        <a href="#/">
            <button style="margin-top: 20px;" class="btn btn-default" ng-click="deleteEmployee(employee._id)">Delete</button>
        </a>
    </div>
    <div class="col-md-1">
    </div>
</div>
<div ng-hide="editMode" class="container">
    <div>
        <p ng-if="employee.age"><b>Age:</b> {{ employee.age }}</p>
        <p ng-if="employee.job"><b>Job:</b> {{ employee.job }}</p>
        <p>
            <button style="margin-top: 20px;" class="btn btn-default" ng-click="toggleEdit()"><span class="glyphicon glyphicon-edit"></span> Edit</button>
            <a style="margin-top: 20px;" class="btn btn-default" href="#/"><span class="glyphicon glyphicon-arrow-left"></span>Back</a>
        </p>
    </div>
</div>

<div ng-include="employeeFormUrl">
</div>

employee-form.html

vi employee-form.html
<div class="row" ng-hide="employee._id">
  <div class="col-md-6">
    <h2>Register New Employee</h2>
  </div>
</div>
<div class="container">
  <div>
    <fieldset class="form-group">
      <label>Name</label>
      <input type="text" class="form-control" id="name" ng-model="employee.name" placeholder="Name" required />
    </fieldset>
    <fieldset class="form-group">
      <div class="row">
        <div class="col-md-3 col-sm-6">
          <label>Age</label>
          <input type="text" class="form-control" id="age" ng-model="employee.age" placeholder="Must be older than 18" required />
        </div>
        <div class="col-md-6 col-md-offset-3 col-sm-6">
          <label>Job</label>
          <input type="text" class="form-control" id="job" ng-model="employee.job" placeholder="E.g. JavaScript Full-Stack Developer" required />
        </div>
      </div>
    </fieldset>
    <fieldset class="form-group">
      <button style="margin-top: 20px;" class="btn btn-default" ng-click="saveEmployee(employee)"><span class="glyphicon glyphicon-save"></span> Save</button>
      <button style="margin-top: 20px;" class="btn btn-default" ng-click="back()"><span class="glyphicon glyphicon-arrow-left"></span> Back</button>
    </fieldset>
  </div>
</div>

There are a lot of stuff that I don't really get from those files.

Those are the components we're going to load in our index.html according to the routes we access. There is still a bit more to be done until our application is ready, but let's take a look at what we've got right now.

The HTML attributes starting with a ng- are AngularJS native directives. Most of them are pretty-much self-explained (such as include and click), while others are not so obvious (model, for instance). Here's a quick and dirty rundown of the directives we're using in this example.

  • ng-hide: will hide the element if the expression given evaluates to true (or any truthy value)
  • ng-if: More or less the same as ng-hide, except it will actually skip rendering the element if the expression given evaluates to false.
  • ng-include: Includes a template into the container
  • ng-model: Performs two-way data binding

Two-way what?!

The app.js file could be considered more or less as the back-end for our view, the Controller layer in a MVC architecture. As a matter of fact, we actually do have to declare and implement controllers. What AngularJS two-way data binding does is keep the bound variable value updated in both layers (view and controller). This means that whatever changes we make on one side will be reflected on the other in real time, and vice-versa.

Declaring our service and controllers

vi app.js

So far, we have only declared our routes, but we need a service to call our Express server endpoints (much like an API) and controllers which will handle data and pass them to our components.

Let's declare our Employee service.

angular.module("employeesApp", ['ngRoute'])
  .config(function($routeProvider) {
    $routeProvider
    .when("/", {
      templateUrl: "list.html",
      controller: "ListController",
      resolve: {
        employees: function(Employees) {
          return Employees.getEmployees();
        }
      }
    })
    .when("/new/employees", {
      controller: "NewEmployeeController",
      templateUrl: "employee-form.html"
    })
    .when("/employees/:employeeId", {
      controller: "ViewEmployeeController",
      templateUrl: "employee.html"
    })
    .when("/edit/employees/:employeeId", {
      controller: "EditEmployeeController",
      templateUrl: "employee-form.html"
    })
    .otherwise({
      redirectTo: "/"
    });
  })
  .service("Employees", function($http) {
    this.getEmployees = function() {
      return $http.get("/employees")
        .then(function(response) {
          return response;
        }, function(response) {
          // Improve error messages
          alert("Error listing employees");
        })
    };
    this.createEmployee = function(employee) {
      return $http.post("/employees", employee)
        .then(function(response) {
          return response;
        }, function(response) {
          alert("Error creating employee");
        });
    };
    this.getEmployeeById = function(employeeId) {
      return $http.get("/employees/" + employeeId)
        .then(function(response) {
          return response;
        }, function(response) {
          alert("Error finding employee");
        });
    };
    this.updateEmployee = function(employee) {
      console.log(employee._id);
      return $http.put("/employees/" + employee._id, employee)
        .then(function(response) {
          return response;
        }, function(response) {
          alert("Error editing this employee");
          console.log(response);
        });
    };
    this.deleteEmployee = function(employeeId) {
      return $http.delete("/employees/" + employeeId)
        .then(function(response) {
          return response;
        }, function(response) {
          alert("Error deleting this employee");
          console.log(response);
        });
    };
  })

Note that we're chaining everything after angular.module("employeesApp"). This is so we don't declare it multiple times (although it doesn't break your app, DRY still applies).

We have now created an Employees service that has handlers for every CRUD operation requesting our Express server endpoints directly. It is possible to create a whole API with Express and host it elsewhere, then serve your AngularJS application with nginx or whatever other service you may like and call those endpoints remotely.

Setting up controllers

For starters, let's create our ListController controller. We already have it set up to a route in our config, pointing to our list.html component. In list.html, we call an employees variable that's seemingly not declared anywhere. We're going to declare it in our controller, like this:

vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; }) .controller("ListController", function(employees, $scope) { $scope.employees = employees.data; })

⚠️ **GitHub.com Fallback** ⚠️