Creating Web Client

    Entry script is a script that handles all application requests. In our case it will be
    file contained in the web directory.

    Add ng-app attribute to html tag. As an example, we’ll use spaApp as the value.

    Define Default Angular Controller

    Add ng-controller attribute to body tag. Controller name is index.

    1. </head>
    2. <!-- define angular controller -->
    3. <body ng-controller="index">

    Create Main Menu

    Add the following content inside body tag:

    1. <body ng-controller="index">
    2. <nav class="navbar navbar-default">
    3. <div class="container">
    4. <div class="navbar-header">
    5. <a class="navbar-brand" href="#/">Single Page Application</a>
    6. </div>
    7. <ul class="nav navbar-nav navbar-right">
    8. <li><a href="#/"><i class="glyphicon glyphicon-home"></i> Home</a></li>
    9. <li><a href="#/site/about"><i class="glyphicon glyphicon-tag"></i> About</a></li>
    10. <li><a href="#/site/contact"><i class="glyphicon glyphicon-envelope"></i> Contact</a></li>
    11. </ul>
    12. </div>
    13. </nav>
    14. <div id="main" class="container">
    15. <!-- angular templating -->
    16. <!-- this is where content will be injected -->
    17. <div ng-view></div>
    18. </div>
    19. <footer class="text-center">
    20. <p>Yii 2.0.3 + AngularJs 1.3.15</p>
    21. </footer>

    Navbar is used for menu, main is page container. Footer is, obviously, a footer.

    Important thing here is an id of in div with container class:

    1. <div id="main" class="container">
    2. <!-- angular templating -->
    3. <!-- this is where content will be injected -->
    4. <div ng-view></div>
    5. </div>

    Dynamic content from other files or page views will be placed into <div ng-view></div>.

    Create Main Module and Sub Module

    The main module is intended to control other scripts such as sub module. We name it app.js and
    place it into the webroot of the web client:

    1. 'use strict';
    2. // adjust to the your url of web service
    3. var serviceBase = 'http://127.0.0.1/web-service/web/'
    4. // declare app level module which depends on views, and components
    5. var spaApp = angular.module('spaApp', [
    6. 'ngRoute',
    7. 'spaApp.site',
    8. ]);
    9. // sub module declaration
    10. var spaApp_site = angular.module('spaApp.site', ['ngRoute'])
    11. spaApp.config(['$routeProvider', function($routeProvider) {
    12. // config default route
    13. $routeProvider.otherwise({redirectTo: '/site/index'});
    14. }]);

    Default route is /site/index. This route will handled by spaApp.site sub module.

    After creating spaApp.site sub module we need to define what that sub module does. Create a file
    in controllers directory.

    1. 'use strict';
    2. spaApp_site.config(['$routeProvider', function($routeProvider) {
    3. $routeProvider
    4. .when('/site/index', {
    5. templateUrl: 'views/site/index.html',
    6. controller: 'index'
    7. })
    8. .when('/site/about', {
    9. templateUrl: 'views/site/about.html',
    10. controller: 'about'
    11. })
    12. .when('/site/contact', {
    13. templateUrl: 'views/site/contact.html',
    14. controller: 'contact'
    15. })
    16. .otherwise({
    17. redirectTo: '/site/index'
    18. });
    19. }])
    20. .controller('index', ['$scope', '$http', function($scope,$http) {
    21. // create a message to display in our view
    22. $scope.message = 'Everyone come and see how good I look!';
    23. }])
    24. .controller('about', ['$scope', '$http', function($scope,$http) {
    25. // create a message to display in our view
    26. $scope.message = 'Look! I am an about page.';
    27. }])
    28. .controller('contact', ['$scope', '$http', function($scope,$http) {
    29. // create a message to display in our view
    30. $scope.message = 'Contact us! JK. This is just a demo.';
    31. }]);
    1. spaApp_site.config(['$routeProvider', function($routeProvider) {
    2. $routeProvider
    3. .when('/site/index', {
    4. templateUrl: 'views/site/index.html',
    5. controller: 'index'
    6. })
    7. ...
    8. ...
    9. .otherwise({
    10. redirectTo: '/site/index'
    11. });
    12. }])

    This is routing configuration of this sub module only. Every route has may templateUrl and controller.

    • templateUrl is an external HTML file that is used as partial content. Quite similar to Yii views.
    • controller is a name of controller that prepares template data such as variables. It is simlar to what Yii controller does.

    .otherwise tells the application what to do if no route matches.

    $scope is a scope that can be handled by the angular app in this case is all the tags under the tag which is marked with ng - app

    $scope.message, message is variabel in file templateUrl, let say views/site/index.html, point to {{message}}

    Include Main Module and Sub Module

    After creating main module app.js and sub module site.js, we must include it in an entry script of app index.html:

    1. <script src="assets/angular/angular-animate.min.js"></script>
    2. <!-- Include this js -->
    3. <script src="app.js"></script>
    4. <script src="controllers/site.js"></script>
    5. </body>

    Create Template File

    Create a template file to be used by controller in directory. The file name would be
    site/index.html:

    1. <div class="jumbotron text-center">
    2. <h1>Home Page</h1>
    3. <p>{{ message }}</p>
    4. </div>

    Create :

    1. <div class="jumbotron text-center">
    2. <h1>Contact Page</h1>
    3. <p>{{ message }}</p>
    4. </div>

    Create site/about.html:

    1. <div class="jumbotron text-center">
    2. <h1>About Page</h1>
    3. <p>{{ message }}</p>
    4. </div>

    These views are simple placeholders for now.

    Test your application



    1. 'use strict';
    2. var serviceBase = 'http://127.0.0.1/web-service/web/'
    3. // Declare app level module which depends on views, and components
    4. 'ngRoute',
    5. 'spaApp.site',
    6. 'spaApp.book',
    7. ]);
    8. var spaApp_site = angular.module('spaApp.site', ['ngRoute'])
    9. var spaApp_book = angular.module('spaApp.book', ['ngRoute']);
    10. spaApp.config(['$routeProvider', function($routeProvider) {
    11. $routeProvider.otherwise({redirectTo: '/site/index'});
    12. }]);

    Create book.js in models directory

    book.js will handle CRUD data provided by REST service is is pretty much what models are doing in Yii.

    1. 'use strict';
    2. spaApp_book.factory("services", ['$http','$location','$route',
    3. function($http,$location,$route) {
    4. var obj = {};
    5. obj.getBooks = function(){
    6. return $http.get(serviceBase + 'books');
    7. }
    8. obj.createBook = function (book) {
    9. return $http.post( serviceBase + 'books', book )
    10. .then( successHandler )
    11. .catch( errorHandler );
    12. function successHandler( result ) {
    13. $location.path('/book/index');
    14. }
    15. function errorHandler( result ){
    16. alert("Error data")
    17. $location.path('/book/create')
    18. }
    19. };
    20. obj.getBook = function(bookID){
    21. return $http.get(serviceBase + 'books/' + bookID);
    22. }
    23. obj.updateBook = function (book) {
    24. return $http.put(serviceBase + 'books/' + book.id, book )
    25. .then( successHandler )
    26. .catch( errorHandler );
    27. function successHandler( result ) {
    28. $location.path('/book/index');
    29. }
    30. function errorHandler( result ){
    31. alert("Error data")
    32. $location.path('/book/update/' + book.id)
    33. }
    34. };
    35. obj.deleteBook = function (bookID) {
    36. return $http.delete(serviceBase + 'books/' + bookID)
    37. .then( successHandler )
    38. .catch( errorHandler );
    39. function successHandler( result ) {
    40. $route.reload();
    41. }
    42. function errorHandler( result ){
    43. alert("Error data")
    44. $route.reload();
    45. }
    46. };
    47. return obj;
    48. }]);

    There are multiple functions such as obj.getBooks, obj.createBook, etc. which are passing data to RESTful endpoints.
    For example, the following will get a list of the books using GET.
    See .

    Create a book using POST:

    1. obj.createBook = function (book) {
    2. return $http.post( serviceBase + 'books', book )

    Update a book using PUT:

    1. obj.updateBook = function (book) {
    2. return $http.put(serviceBase + 'books/' + book.id, book )

    Create a controller for Site Sub Module

    Create book.js in controllers directory. It will handle book views like Yii controller
    does:

    1. 'use strict';
    2. spaApp_book.config(['$routeProvider', function($routeProvider) {
    3. $routeProvider
    4. .when('/book/index', {
    5. templateUrl: 'views/book/index.html',
    6. controller: 'index'
    7. })
    8. .when('/book/create', {
    9. templateUrl: 'views/book/create.html',
    10. controller: 'create',
    11. resolve: {
    12. book: function(services, $route){
    13. return services.getBooks();
    14. }
    15. }
    16. })
    17. .when('/book/update/:bookId', {
    18. templateUrl: 'views/book/update.html',
    19. controller: 'update',
    20. resolve: {
    21. book: function(services, $route){
    22. var bookId = $route.current.params.bookId;
    23. return services.getBook(bookId);
    24. }
    25. }
    26. })
    27. .when('/book/delete/:bookId', {
    28. templateUrl: 'views/book/index.html',
    29. controller: 'delete',
    30. })
    31. .otherwise({
    32. redirectTo: '/book/index'
    33. });
    34. }]);
    35. spaApp_book.controller('index', ['$scope', '$http', 'services',
    36. function($scope,$http,services) {
    37. $scope.message = 'Everyone come and see how good I look!';
    38. services.getBooks().then(function(data){
    39. $scope.books = data.data;
    40. });
    41. $scope.deleteBook = function(bookID) {
    42. if(confirm("Are you sure to delete book number: " + bookID)==true && bookID>0){
    43. services.deleteBook(bookID);
    44. $route.reload();
    45. }
    46. };
    47. }])
    48. .controller('create', ['$scope', '$http', 'services','$location','book',
    49. function($scope,$http,services,$location,book) {
    50. $scope.message = 'Look! I am an about page.';
    51. $scope.createBook = function(book) {
    52. var results = services.createBook(book);
    53. }
    54. }])
    55. .controller('update', ['$scope', '$http', '$routeParams', 'services','$location','book',
    56. function($scope,$http,$routeParams,services,$location,book) {
    57. $scope.message = 'Contact us! JK. This is just a demo.';
    58. var original = book.data;
    59. $scope.book = angular.copy(original);
    60. $scope.isClean = function() {
    61. }
    62. $scope.updateBook = function(book) {
    63. var results = services.updateBook(book);
    64. }]);

    Create Template File for Book Sub Module

    Create template file that is pointed by controller in book sub module in directory.
    The name is book/index.html:

    1. <div>
    2. <h1>BOOK CRUD</h1>
    3. <p>{{ message }}</p>
    4. <div ng-show="books.length > 0">
    5. <a class="btn btn-primary" href="#/book/create">
    6. <i class="glyphicon glyphicon-plus"></i> Create
    7. </a>
    8. <table class="table table-striped table-hover">
    9. <thead>
    10. <th>Title</th>
    11. <th>Author</th>
    12. <th>Publisher</th>
    13. <th>Year</th>
    14. <th style="width:80px;">Action&nbsp;</th>
    15. </thead>
    16. <tbody>
    17. <tr ng-repeat="data in books">
    18. <td>{{data.title}}</td>
    19. <td>{{data.author}}</td>
    20. <td>{{data.publisher}}</td>
    21. <td>{{data.year}}</td>
    22. <td>
    23. <a class="btn btn-primary btn-xs" href="#/book/update/{{data.id}}">
    24. <i class="glyphicon glyphicon-pencil"></i>
    25. </a>
    26. <a class="btn btn-danger btn-xs" ng-click="deleteBook(data.id)">
    27. <i class="glyphicon glyphicon-trash"></i>
    28. </a>
    29. </td>
    30. </tr>
    31. </tbody>
    32. </table>
    33. </div>
    34. <div ng-show="books.length == 0">
    35. Empty
    36. </div>
    37. </div>

    Create :

    1. <div>
    2. <h1>BOOK CRUD</h1>
    3. <p>{{ message }}</p>
    4. <form role="form" name="myForm">
    5. <div class= "form-group" ng-class="{error: myForm.title.$invalid}">
    6. <label> Title </label>
    7. <div>
    8. <input name="title" ng-model="book.title" type= "text" class= "form-control" placeholder="Title" required/>
    9. <span ng-show="myForm.title.$dirty && myForm.title.$invalid" class="help-inline">Title Required</span>
    10. </div>
    11. </div>
    12. <div class= "form-group">
    13. <label> Description </label>
    14. <div>
    15. <textarea name="description" ng-model="book.description" class= "form-control" placeholder= "Description"></textarea>
    16. </div>
    17. </div>
    18. <div class= "form-group" ng-class="{error: myForm.author.$invalid}">
    19. <label> Author </label>
    20. <div>
    21. <input name="author" ng-model="book.author" type= "text" class= "form-control" placeholder="Author" required/>
    22. <span ng-show="myForm.author.$dirty && myForm.author.$invalid" class="help-inline">Author Required</span>
    23. </div>
    24. </div>
    25. <div class= "form-group" ng-class="{error: myForm.publisher.$invalid}">
    26. <label> Publisher </label>
    27. <div>
    28. <input name="publisher" ng-model="book.publisher" type= "text" class= "form-control" placeholder="Publisher" required/>
    29. <span ng-show="myForm.publisher.$dirty && myForm.publisher.$invalid" class="help-inline">Publisher Required</span>
    30. </div>
    31. </div>
    32. <div class= "form-group" ng-class="{error: myForm.year.$invalid}">
    33. <label> Year </label>
    34. <div>
    35. <input name="year" ng-model="book.year" type= "text" class= "form-control" placeholder="Year" required/>
    36. <span ng-show="myForm.year.$dirty && myForm.year.$invalid" class="help-inline">Year Required</span>
    37. </div>
    38. </div>
    39. <a href="#/book/index" class="btn btn-default">Cancel</a>
    40. <button ng-click="createBook(book);"
    41. ng-disabled="myForm.$invalid"
    42. type="submit" class="btn btn-default">Submit</button>
    43. </form>
    44. </div>

    Create book/update.html:

    1. <div>
    2. <h1>BOOK CRUD</h1>
    3. <p>{{ message }}</p>
    4. <form role="form" name="myForm">
    5. <div class= "form-group" ng-class="{error: myForm.title.$invalid}">
    6. <label> Title </label>
    7. <div>
    8. <input name="title" ng-model="book.title" type= "text" class= "form-control" placeholder="Title" required/>
    9. <span ng-show="myForm.title.$dirty && myForm.title.$invalid" class="help-inline">Title Required</span>
    10. </div>
    11. </div>
    12. <div class= "form-group">
    13. <label> Description </label>
    14. <div>
    15. <textarea name="description" ng-model="book.description" class= "form-control" placeholder= "Description"></textarea>
    16. </div>
    17. </div>
    18. <div class= "form-group" ng-class="{error: myForm.author.$invalid}">
    19. <label> Author </label>
    20. <div>
    21. <input name="author" ng-model="book.author" type= "text" class= "form-control" placeholder="Author" required/>
    22. <span ng-show="myForm.author.$dirty && myForm.author.$invalid" class="help-inline">Author Required</span>
    23. </div>
    24. </div>
    25. <div class= "form-group" ng-class="{error: myForm.publisher.$invalid}">
    26. <label> Publisher </label>
    27. <div>
    28. <input name="publisher" ng-model="book.publisher" type= "text" class= "form-control" placeholder="Publisher" required/>
    29. <span ng-show="myForm.publisher.$dirty && myForm.publisher.$invalid" class="help-inline">Publisher Required</span>
    30. </div>
    31. </div>
    32. <div class= "form-group" ng-class="{error: myForm.year.$invalid}">
    33. <label> Year </label>
    34. <div>
    35. <input name="year" ng-model="book.year" type= "text" class= "form-control" placeholder="Year" required/>
    36. <span ng-show="myForm.year.$dirty && myForm.year.$invalid" class="help-inline">Year Required</span>
    37. </div>
    38. </div>
    39. <a href="#/book/index" class="btn btn-default">Cancel</a>
    40. <button ng-click="updateBook(book);"
    41. ng-disabled="isClean() || myForm.$invalid"
    42. type="submit" class="btn btn-default">Submit</button>
    43. </div>

    Don’t forget to add link to book CRUD.

    Test it

    Create Web Client - 图1