AngularJS Tutorial - 3

New version here

The form is working correctly, and we can navigate from and to the contact detail. But something is missing, why show a completely different page when we could open a nifty modal dialog like any application in these days?

The main template

To do this we should first include a new script, ui-bootstrap at the end of our scripts. This will add the ability to create easily (more or less) modal dialogs.

<!DOCTYPE html>
<html>
    <head>
        ...
        <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.js"></script>
        <script type="text/javascript" src="http://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.6.0.js"></script>
        <script type="text/javascript" src ="assets/js/app.js"></script>
    </body>
</html>

The AngualrJS dialog

The usage is pretty simple. We should do two steps: the function to open the dialog and elaborate its results, and the controller/view that will handle the dialog lifem, that will follow the routing setup conventions. The complete documentation can be found on UI-Bootsrap website.

Upon closing a function is called to pass parameters on the caller scope or to do other operations

$scope.valueToPass = "I must be passed";

var modalInstance = $modal.open({
    templateUrl: 'theDialogPartial.html',
    controller: 'TheDialogController',
    resolve: {
        aValue: function () {
            return $scope.valueToPass;
        }
    }
});
modalInstance.result.then(function (paramFromDialog) {
    $scope.paramFromDialog = paramFromDialog;
});

Then a controller can be created, to handle the operations on the dialog. The $modalInstance is the service that is initialize by the previously declared function inside the $modal service.

Here we implement a close function, in wich we invoke the $modalInstance.close. This will invoke the 'promise' (the then in the previous script and will set on the scope the variable paramFromDialog with the value "Someone Closed Me".

app.controller('TheDialogController',function($scope, $modalInstance, aValue) {
    $scope.valuePassed = aValue;
    $scope.close = function () {
        $modalInstance.close("Someone Closed Me");
    };
});

Note that the scopes of the controller is a child scope for the one in the "modelInstance" script. Then if we need to pass data to the controller we must explicitly add the parameter "resolve" to the "$modal.open" call in wich we will set the parameter with the name that will have into the controller instance

The partial view. There is a specific css styling for the dialog withing bootstrap and we will change the partial accordingly, with the 'modal-header', 'modal-body' and 'modal-footer' classes.

Inside this view is shown the "valuePassed", that will have the value "I must be passed"

<div class="modal-header">
    <h2>The title</h2>
</div>   
<div class="modal-body">
    The body of the dialog with the value to pass '{{valuePassed}}'
</div>
<div class="modal-footer">
    <button class="btn" ng-click="close()">Close</button>
</div>

The ContactList. Opening a dialog

A new button had been added instead of the link to the detail, the function "open" associated with the current scope, is invoked during the on-click event. This will happens through the "ng-click" attribute. As you can see the scope inside the "ng-repeat" contains the variable "contact" that we can use directly in javascript/ We will se in the controller how this is initialized.

<h2>Contacts</h2>
<table class="table table-condensed" ng-controller="ContactDetailController">
    <thead>
        <tr>
            <th>First Name</th>
            <th>Last Name</th>
            <th>Go to detail</th>
        </tr>
    </thead>
    <tbody>
        <tr ng-repeat="contact in contacts">
            <td>{{contact.name}}</td>
            <td>{{contact.surname}}</td>
            <td><button class="btn" ng-click="open(contact.id)" >Detail</button></td>
        </tr>
    </tbody>
</table>
<a class="btn btn-primary" >Add New Contact</a>

The App.js

We remove the contactsDetail route. Since now all will happen as a single page application! But we must add the dependency from UI-Bootstrap. This is the second thing to do with the inclusion of the UI-Bootstrap javscript.

var app = angular.module('ContactsApp', ['ui.bootstrap']);

ContactDetailController

The ContactDetailController will be splitted into

Inside the detail add the open function (that we used inside the contactList), that after getting the contact will store the contact on the context and opens the modal dialog passing the $scope.contact as "contact" to the ModalContactDetailController.

app.controller('ContactDetailController',function($scope, $modal, $http) {
    $scope.open = function (contactId) {
        $http.get('api/contacts/?id='+contactId).success(function(data) {
            $scope.contact = data.data;
            var modalInstance = $modal.open({
                templateUrl: 'assets/partials/contactsDetail.html',
                controller: 'ModalContactDetailController',
                resolve: {
                    contact: function () {
                        return $scope.contact;
                    }
                }
            });
        });
    };
});

ModalContactDetailController

The $scope of the controller is initialized through the modalInstance (note the same name specified inside the ContactDetailController). This scope will be used to fill the contactDetail.

Then a function ok is added to the dialog controller to allow the closing of the modal dialog.

app.controller('ModalContactDetailController',function($scope, $modalInstance, contact) {
    $scope.contact = contact;
    $scope.ok = function () {
        $modalInstance.close();
    };
});

The New ContactDetail

The function 'ok' specified into the ModalContactDetailController is associate with the close button

<div class="modal-header">
    <h2>Contact Detail</h2>
</div>   
<div class="modal-body">
    <label for="surname">First Name:</label> {{contact.name}}<br>
    <label for="surname">Last Name:</label> {{contact.surname}}<br>
    <label for="address">Address:</label> {{contact.address}}<br>
    <label for="phone">Phone:</label> {{contact.phone}}<br>
</div>
<div class="modal-footer">
    <button class="btn btn-primary" ng-click="ok()">OK</button>
</div>

Screenshot

Download the sample source


Last modified on: September 06, 2014