Introduction to AngularJS

Some notes going over an example on AngularJS

 

@section scripts{    
   <script src="~/Scripts/angular.js"></script>
   <script src="~/Scripts/angular-route.js"></script>
   <script src="~/Scripts/angular-resource.js"></script>
   <script src="~/Scripts/angular-animate.js"></script>
   <script src="~/Client/Scripts/AtTheMovies.js"></script>
   <script src="~/Client/Scripts/MovieService.js"></script>
   <script src="~/Client/Scripts/ListController.js"></script>
   <script src="~/Client/Scripts/DetailsController.js"></script>
   <script src="~/Client/Scripts/EditController.js"></script>
}

<h1>At the movies</h1>
<div data-ng-app>
   {{true ? "true" : "false"}}
</div>

Module = is an abstraction that allows you to group various components to keep them isolated from other components and pieces of code in application. One benefit is isolation to make easier unit test.

(function () {
   var app = angular.module("atTheMovies", []);
}());

 

angular” is keyword for the global Angular object, much like $ for jQuery

 

The “data-ng-appdirective instructs angular to load the module into this section. This directive conforms to HTML standards which states that any custom directive must start with “data-

<div data-ng-app="atTheMovies">
   <div ng-controller="ListController">
       {{message}}
   </div>
</div>

 

The $scope variable is an object constructed by Angular and passed as a parameter to the controller function. The controller’s responsibility is to initialize $scope with data and behavior, because $scope is ultimately the model object consumed by the view.

  • Controllers are responsible for putting together a model by augmenting the $scope variable. Controllers avoid manipulating the DOM directly. Instead, changes in the UI are propagated by updating information in the model that the view consumes.
  • The model object is unaware of the view and controller. The model is only responsible for holding state as well as exposing some behavior to manipulate the state.
  • The view uses templates and directives to gain access to the model and present information. This separation of concerns in an Angular application is closer to the Model View View Model (MVVM) design pattern in XAML-based applications than it is to a true MVC design pattern.

 

Services in Angular are objects that perform specific tasks, such as communicate over HTTP, manage the browser history, perform localization, implement DOM compilation, and more. Services, like controllers, are registered in a module and managed by Angular.

For example, one service that comes with Angular out of the box is the $http service, which exposes methods to make async HTTP requests.

How does Angular know the $http parameter is asking for the $http service? Because all components in Angular are registered by name, and $http is the name of the service that communicates with HTTP on the network. Angular literally looks at the source code to the function and inspects the parameter names, which is also how it recognizes that the controller needs a $scope object.

Angular injector (DI) is responsible for providing an instance of $http service.

Because Angular relies on the names of the parameters, you must be careful if you minify your scripts because most JavaScript minifiers change local variables and function parameter names to make the names as short as possible (thereby making the overall script smaller for download)


(function (app) {
   var ListController = function ($scope, $http) { // scope if view model, http is service
       $http.get("/api/movies")
           .success(function (data) {
               $scope.movies = data;
           });
   };
   ListController.$inject = ["$scope", "$http"]; //annotates the names in case minifier changes it
   app.controller("ListController", ListController);
}(angular.module("atTheMovies")));

<div data-ng-app="atTheMovies">
   <div ng-controller="ListController">
       Total Movies: {{movies.length}}
       <table>
           <tr ng-repeat="movie in movies">
               <td>{{movie.title}}</td>
           </tr>
       </table>
   </div>
</div>

The $http service has an API that includes methods such as get, post, put, and delete, and these methods each map to a corresponding HTTP verb of the same name. Thus, the new code in the last snippet is sending an HTTP GET request to the URL /api/movie. The return value is a promise object.

 

Promise objects have become popular in JavaScript libraries over the years because they offer an alternative to callback functions. Promise objects get their name because they promise to deliver a result in the future, and Angular uses promises for most asynchronous behavior, like network calls and timers.

 

Routing

Routing in angular is similar to MVC. Can set /home/index/#details/4 to be some controller, view and model.

Use AngularJS.Route

 

Update the main module – atTheMovies with a list, details and default view

(function () {
   var app = angular.module("atTheMovies", ["ngRoute"]);
   // setting up routing
   var config = function ($routeProvider) {
       $routeProvider // chain the different routes
           .when("/list",
               { templateUrl: "/Client/Views/list.html" })
           .when("/details/:id",
               { templateUrl: "/Client/Views/details.html" })
           .otherwise(
               { redirectTo: "/list" });
   };
   app.config(config);
}());

 

Views

Setup html views in the views folder. These will be called based on the controller tied to the view. Example – details.html:

<div ng-controller="DetailsController">
   {{movie}}
   <h2>{{movie.title}}</h2>
   <div>
       Released in {{movie.releaseYear}}.
   </div>
   <div>
       {{movie.runtime}} minutes long.
   </div>
</div>

 

Service

Creating services allows centralization of http call so that it doesn’t have to be done by each controller.

(function (app) {
   var movieService = function ($http, movieApiUrl) {
       var getAll = function () {
           return $http.get(movieApiUrl);
       };

       var getById = function (id) {
           return $http.get(movieApiUrl + id);
       };

       var update = function (movie) {
           return $http.put(movieApiUrl + movie.Id, movie);
       };

       var create = function (movie) {
           return $http.post(movieApiUrl, movie);
       };

       var destroy = function (movie) {
           return $http.delete(movieApiUrl + movie.Id);
       };

       return {
           getAll: getAll,
           getById: getById,
           update: update,
           create: create,
           delete: destroy
       };
   };

   app.factory("movieService", movieService);
}(angular.module("atTheMovies")))

 

The movieApiUrl is a constant variable that is defined in the main module js file

(function () {
   var app = angular.module("atTheMovies", ["ngRoute"]);

   // setting up routing
   var config = function ($routeProvider) {
       $routeProvider // chain the different routes
           .when("/list",
               { templateUrl: "/Client/Views/list.html" })
           .when("/details/:id",
               { templateUrl: "/Client/Views/details.html" })
           .when("/raw",
               { templateUrl: "/Client/Views/raw.html" })
           .otherwise(
               { redirectTo: "/list" });
   };
   app.config(config);
   app.constant("movieApiUrl", "/api/movie/"); // constant variable - used by movie service
}());

 

Delete

Update the list view to include a delete button, which is now handled by the list controller. Controlled still uses the movie service to perform the delete.

<div ng-controller="ListController">
   Total Movies: {{movies.length}}
   <table class="table">
       <tr ng-repeat="movie in movies">
           <td>{{movie.title}}</td>
           <td>
               <a class="btn btn-default" href="#/details/{{movie.id}}">
                   Details
               </a>
               <button class="btn btn-default" ng-click="delete(movie)">
                   Delete
               </button>
           </td>
       </tr>
   </table>
   <a href="#/raw/">raw</a>
</div>

 

Controller:

(function (app) {
   var ListController = function ($scope, movieService) {
       movieService
           .getAll()
           .success(function (data) {
               $scope.movies = data;
           });
       $scope.delete = function (movie) {
           movieService
               .delete(movie)
               .success(function () {
                   removeMovieById(movie.Id);
               });
       };

       var removeMovieById = function (id) {
           for (var i = 0; i < $scope.movies.length; i++) {
               if ($scope.movies[i].Id == id) {
                   $scope.movies.splice(i, 1);
                   break;
               }
           }
       };
   };
   app.controller("ListController", ListController);
}(angular.module("atTheMovies")));

 

Editing Data

When working with data modification, we should use models. Having models means we need to bind them to the forms. We use ng-modal and ng-show for this.