Step 2 - Create the Angular Customer List

Under Construction

In this step we'll build on the stock template install of the HTML and JavaScript page that gives a simple Angular skeleton application. In this page we'll display a list of customers, with options to edit and then update and delete customers.

The end result will look something like this:

IMAGE TO BE ADDED WITH COMPLETED CODE

Displaying a Customer List

The first thing we'll do is create a customer list that shows us just the as an HTML display, which looks something like this initially:

Let's start with the JavaScript for this code by adding some code to the Page Controller. We'll start with a static list so you can see the list rendering work:

function pageController($scope, $http, $timeout) {

    var vm = this;
    vm.customers = [
        {
            firstName: "Rick",
            lastName: "Strahl",
            company: "West Wind Techologies",
            address: "32 Kaiea Place\nPaia, Hawaii",
            email: "rstrahl@west-wind.com",
            phone: "(808) 321-1231"
        },
        {
            firstName: "Markus",
            lastName: "Egger",
            company: "EPS Software",
            address: "312 Park Ave.\nWailea, Hawaii",
            email: "markus@eps-software.com",
            phone: "(808) 421-1231"
        }
    ];
    
    // Initialization
    initialize();    

    return;

    // Interface function implementations

    function initialize() {
        console.log("page controller started.");
    }
}

This code basically adds a new .customers array property to the pageController. This property then becomes available in the HTML page where the page controller is referenced with ng-controller="pageController".

Let's look at the corresponding HTML to render this out this list. The key items in the code below are the ng-controller attribute at the container, the ng-repeat attribute at the repeating list item, and the {{ viewModelExpressions }} inside of the ng-repeat template:

<div class="container"  ng-controller="pageController as vm">
    <div class="page-header-text">
        <i class="fa fa-list-alt"></i> 
        Customer Angular Demo
    </div>

    <div class="customer-list-item" ng-repeat="customer in vm.customers">
        <div class="customer-header">
            <i class="fa fa-user"></i>
            {{customer.company}}
        </div>
        <div class="customer-body-container">
            <div class="customer-subheader">
                {{customer.firstName}} {{customer.lastName}}
            </div>
            <div class="small">
                {{customer.email}} &bullet; {{customer.phone}}
                <br/>
                {{customer.address}}
            </div>
        </div>
    </div>

    <style>
        .customer-list-item {
            padding: 5px;
            border-bottom: 1px silver solid;
        }
        .customer-list-item:hover {
            background-color: khaki;
            transition: all 0.5s ease-out;;
        }
        .customer-header {
            font-size: 1.3em;
            font-weight: bold;
            color: steelblue;
        }
        .customer-subheader {
            font-size: 1.1em;
            color: #535353;
            font-weight: bold;                    
        }
        .customer-body-container {
            padding: 0 25px;
        }                
    </style>

</div>

Note: I'm including the CSS here so that you can see the formatting. The CSS is actually loaded inside of the <head> tag of the HTML page.

So what's happening in this code? First we bind the page controller to the area of the page that it needs to manage - in this case the container. ng-controller can be applied to any container DOM element, including the top level <body> element, but since you can have multiple controllers on a single page you typically want to have it scoped as close as possible to the area you're working in. Note that you can have multiple controllers and you can also nest them.

So the controller is hooked up:

ng-controller="pageController as vm"

which says, make the pageController as a variable called vm (for View Model). This makes the vm object available with any of the properties on the pageController. So we created a .customers property that holds two customers and these can be referenced as {{vm.customers}}. Now this happens to be a list. if you do:

<div>{{vm.customers}}</div>

which actually produces a JSON string to display. Not that useful. However you could also try:

<div>{{vm.customers[0].company}}</div>

which displays the company of the first customer. In short, any property on the pageController is available for you to bind to using the {{ }} syntax.

Using ng-repeat to bind a List of Objects

Typically when you bind an array of items you want to loop over the list and render multiple items. So in the code above we use the ng-repeat directive to iterate over each of the items and produce a customer child instance we can then bind to.

In its simplest form this works like this:

<div class="customer-list-item" ng-repeat="customer in vm.customers">
    {{customer.firstName}} {{customer.lastName}}
    <hr/>
</div>

which spits out a list of all the customer names from the list. The more complex HTML you see in the larger code snippet above does just that except it embeds multiple expression into HTML that is a little more complex.

Live Bindings

What I've described so far is basic one way binding using templates, which is cool, but nothing so different then what we used in the jQuery example.

The big difference is that Angular actually binds the list in such a way if you change a value in the model that is bound by Angular, that change is immediately reflected in the display. For example, if I change the first customer's company to a new value in code or via user input the list rendered above is immediately updated without any explicit code on our part.

To demonstrate here's a silly demonstration: Add an input fields below the company display in the list that allows live editing for the company field on each item:

<div class="customer-header">
    <i class="fa fa-user"></i>
    {{customer.company}}
</div>
<input type="text" ng-model="customer.company"
       class="form-control"                       
       placeholder="Company" />

The input field has an ng-model attribute binds the customer.company for two-way updates to the input control. So when you type into the textbox the value is immediately updated in the customer object in the array and that change immediately reflects in the rendered list as you type each letter:

Cool right? Two way, real time data binding! So rather than updating the value in the model explicitly by assigning a value to a DOM element, Angular re-renders the DOM based on any changes to the model.

Model Updates over DOM Updates

A key feature of Angular is:

To affect UI changes you update the Model, not manipulate the DOM directly

The beauty of Angular is that you can simply update a value on your model, and see that change immediately reflected in the UI, without having to manually assign it to the DOM. This a key aspect of working with Angular where the goal is to be able to use simple code assignments to manipulate UI behavior.

Loading data from the REST Service

Ok, so in the last example I used a static array to hold the customer list. Let's get the customer data from our REST service instead. Add a new function to pageController like this:

function loadCustomers() {
    return $http.get("customers.csvc")
        .success(function (customers) {
                vm.customers = customers;
        })
        .error(function() {
                var error = ww.angular.parseHttpError(arguments);
                toastr.error(error.message);
            });

}

This code uses the $http service that Angular provides to make an HTTP call to the server. $http includes .get, .post, .delete etc methods that map to the common HTTP verbs you might use to call your server. Here we use .get to simply retrieve the customer list.

$http.get() returns a Promise object that you can use to attach the .success() and .error() handlers to that respond to the result of the HTTP service call.

JavaScript Promises

Promises are objects that represent an asynchronous operation. A promise wraps an async operation and provides methods that can attach to success and failure handlers - typically using .then() and .catch() although some objects like $http also support .success() and .error(). Multiple handlers can be attached to a single promise and because a promise is an object the promise can be passed around an application. Promises are a more sophisticated alternative to callbacks passed to methods and they provide distinct advantages because you pass the promise around an application and attach multiple handlers.

The $http service uses .success() to receive the deserialized JSON response from our Customers.cscv request, which contains the customer list.

Now we need to get this code to fire by adding it to the initialize() function that is fired when the controller initially loads so the customers load immediately:

function initialize() {
    console.log("page controller started.");
    loadCustomers();
}

The whole controller now looks like this:

function pageController($scope, $http, $timeout) {

    var vm = this;
    vm.customers = [];

    // Initialization
    initialize();    

    return;

    // Interface function implementations

    function initialize() {
        console.log("page controller started.");
        loadCustomers();
    }

    function loadCustomers() {
        return $http.get("customers.csvc")
            .success(function (customers) {
                    debugger;
                    vm.customers = customers;
            })
            .error(function() {
                    var error = ww.angular.parseHttpError(arguments);
                    toastr.error(error.message);
                });

    }
}

When you reload the page now, you should see a much longer list of customers displayed with the data from the server database.


© West Wind Technologies, 1996-2019 • Updated: 02/18/16
Comment or report problem with topic