Lesson 6: Modules

As our application grows, we need to consider the possibility of splitting it into different modules. It comes with it a lot of advantages, thus helping us to find the best way to test and evolve each module separately from the others and also to share each module with other projects.

In this Lesson, we are going to cover the following topics:

  • How to create modules
  • Recommended modules

Creating modules

By gaining an in-depth understanding of the underlying business inside our application, we can isolate each group of functionalities (which are correlated) into a separated module. In the case of our parking application, we can split it into three different modules:

  • UI: This module gives directives that could be used by other projects such as alert, accordion, modal, tab, and tooltip.
  • Search: The search engine we created to filter cars could also be separated as an individual library and reused in other places.
  • Parking: This is the parking application itself, with its own resources such as views, controllers, directives, filters, and services.

First, we need to create each new module separately and then they need to be declared inside the parking application module such that they are available.

The UI module

The UI module will contain the directives that we created in Lesson 2, Creating Reusable Components with Directives.

To create an isolated and easy-to-use module, we should consider placing the entire code inside a unique file.

For now, let's start by creating our new module called ui in the app.js file, as follows:

var ui = angular.module("ui", []);

After that, we will declare each component separated in its own file. This will improve the maintainability of the module, facilitating the access to the components. The template is another aspect that we need to take care. In Lesson 2, Creating Reusable Components with Directives, we separated it from the directive's code. However, though we want to deliver this library in an easier format, it would be a good choice to embed its code within the component.

There are plugins for Grunt, such as grunt-html-to-js that may perform this tough and boring job for us. Consider the following code snippet in the alertDirective.js file:

ui.directive("alert", function () {
  return {
    restrict: 'E',
    scope: {
      topic: '@'
    },
    replace: true,
    transclude: true,
    template: 
      "<div class='alert'>" +
        "<span class='alert-topic'>" +
          "{{topic}}" +
        "</span>" +
        "<span class='alert-description' ng-transclude>" +
        "</span>" +
      "</div>"
  };
});

Consider the following code snippet in the accordionDirective.js file:

ui.directive("accordion", function () {
  return {
    restrict: "E",
    transclude: true,
    controller: function ($scope, $element, $attrs, $transclude) {
      var accordionItens = [];

      var addAccordionItem = function (accordionScope) {
        accordionItens.push(accordionScope);
      };
   
      var closeAll = function () {
        angular.forEach(accordionItens, function (accordionScope) {
          accordionScope.active = false;
        });
      };
   
      return {
        addAccordionItem: addAccordionItem,
        closeAll: closeAll
      };
    },
    template: "<div ng-transclude></div>"
  };
});

ui.directive("accordionItem", function () {
  return {
    restrict: "E",
    scope: {
      title: "@"
    },
    transclude: true,
    require: "^accordion",
    link: function (scope, element, attrs, ctrl, transcludeFn) {
      ctrl.addAccordionItem(scope);
      element.bind("click", function () {
        ctrl.closeAll();
        scope.$apply(function () {
          scope.active = !scope.active;
        });
      });
    },
    template: 
      "<div class='accordion-item'>" +
        "{{title}}" +
      "</div>" +
      "<div " +
        "ng-show='active' " +
        "class='accordion-description' " +
        "ng-transclude" +
      ">" +
      "</div>"  
  };
});

Great! Now we are ready to pack our library inside one script file. For this, again, we may rely on Grunt, through the grunt-contrib-concat plugin, for creating this concatenation for us. The destination file in this case would be ui.js, and we are going to declare it inside the index.html file of our parking application.

The search module

The search module will contain carSearchService, which we created in Lesson 4, Dependency Injection and Services.

Again, we are going to start by declaring the module search in the app.js file, as follows:

var search = angular.module("search", []);

Because we want to deliver this service as a reusable component, it would be nice to get rid of the car concept, making it more generic. To do that, let's just change it from car to entity. Consider the following code snippet in the searchService.js file:

search.factory('searchService', function ($timeout, $q) {
  var _filter = function (entities, criteria) {
    var deferred = $q.defer();
    $timeout(function () {
      var result = [];
      angular.forEach(entities, function (entity) {
        if (_matches(entity, criteria)) {
          result.push(entity);
        }
      });
      if (result.length > 0) {
        deferred.resolve(result);
      } else {
        deferred.reject("No results were found!");
      }
    }, 1000);
    return deferred.promise;
  };

  var _matches = function (entity, criteria) {
    return angular.toJson(entity).indexOf(criteria) > 0;
  };

  return {
    filter: _filter
  }
});

Now that our search module is ready, we can use it with any project we want! The name of this script, after the files, concatenation, will be search.js, and we need to import it to the index.html file.

The parking application module

It's time to create our application module and declare our new modules ui and search as our dependencies. Also, we need to include the ngRoute and ngAnimate modules in order to to enable the routing and animation mechanisms. Consider the following code snippet in the app.js file:

var parking = angular.module("parking", ["ngRoute", "ngAnimate", "ui", "search"]);

That's it! Now, we just need to import the scripts inside our index.html file, as follows:

<!doctype html>
<html ng-app="parking">
  <head>
    <title>[Packt] Parking</title>
    <!-- Application CSS -->
    <link rel="stylesheet" type="text/css" href="css/app.css">
    <!-- Application Libraries -->
    <script src="lib/angular.js"></script>
    <script src="lib/angular-route.js"></script>
    <script src="lib/angular-animate.js"></script>
    <script src="lib/ui.js"></script>
    <script src="lib/search.js"></script>
    <!-- Application Scritps -->
    <script src="js/app.js"></script>
    <script src="js/constants.js"></script>
    <script src="js/controllers.js"></script>
    <script src="js/filters.js"></script>
    <script src="js/services.js"></script>
    <script src="js/config.js"></script>
    <script src="js/run.js"></script>
  </head>
  <body>
    <div ng-view></div>
  </body>
</html>

A major part of the applications has concepts, which we could think of developing as a separated module. Beyond this, it is an excellent opportunity to contribute by opening the source code and evolving it with the community!

Recommended modules

AngularJS has a huge community and thousands of modules available for use. There are lots of things that we actually don't need to worry about while developing something by ourselves! From tons of UI components to the integration with many of the most well-known JavaScript libraries such as Highcharts, Google Maps and Analytics, Bootstrap, Foundation, Facebook, and many others, you may find more than 500 modules on the Angular Modules website, at www.ngmodules.org.

Recommended modules
Recommended modules
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.11.182