Skip to main content

Angular + Require project template

I've been working on an Angular project for good number months. There's a lot that I've learned and I've realized that the code I wrote could have been structured in a better way. I wanted to write this post sometime back, however I thought it would be better to create an application structure first and then post my learnings. I have posted all the code on github here - https://github.com/sagar-ganatra/angular-require-template. The template is still a work in progress, however the basic structure of the template is in place.


Motivation:
I always visualized a web page broken down into multiple components that are completely decoupled and components that can be reused. For example, a component or a widget that displays a chart does not have to know about the navbar in the page. It would however provide an interface through which external components would interact or change the state of it.

Why RequireJS?
In my Angular application's index.html file, I had included various script blocks that looked like this:

<script src="../bower_components/jquery/jquery.js"></script>
<script src="../bower_components/angular/angular.js"></script>
<script src="../bower_components/angular-bootstrap/ui-bootstrap-tpls.js"></script>
<script src="../bower_components/angular-cookies/angular-cookies.js"></script>
<script src="../bower_components/angular-route/angular-route.js"></script>

Here the script tags are included in such a way that the dependent files come first and then the others are listed. Every time I added a new script file in the project, I had to update the index.html file and ensure that the dependencies are always included first. Instead, I could use a RequireJS shim to declare the dependencies:

shim: {
    angular: {
        deps: ['jquery'],
        exports: 'angular'
    },
        
    angularMocks: {
        deps: ['angular']  
    },
        
    angularCookies: {
        deps: ['angular']
    },
        
    uirouter: {
        deps: ['angular']
    }
}


This is more declarative and less prone to errors.

This is not the only reason I would use RequireJS in my project, one of the other factors and the most important one is to provide structure to the application. I want my components to be independent or individual widgets that can be reused. When creating components I would make use of the directive interface which can then be included anywhere in the project. For example, the interface for a navbar could look like:

<navbar title="{{title}}"></navbar>

Here the navbar element has the title attribute which would then become a scope variable for the navbar directive. Essentially everything on the page would be a collection of directives which would then be compiled and the resultant HTML markup would be injected into the DOM:


Here the directive serves as a gateway to the service that we are trying to add to the application. A directive is an individual widget which is not aware of other directives used in the page and it's service agnostic. Here in our example, the playersList directive would consume list of players and perform some action when a player is selected. The directive would provide an interface and the page that wants to use the directive can then provide the data:

<div players-list
     players="players"
     on-player-select="showPlayerStats(playerId)"
     selected-player="selectedPlayerId">
</div>

Here the values provided to various attributes are defined in the controller scope. In this way, the directive remains agnostic of the data or the service that it should talk to.

In my project template, I've create a module for each directive. In this example, we would have two modules - navbarModule, playersStatsModule. I would include playersList and playerDetails directive into one single module because they serve as one entity. However, they are completely decoupled and don't interact with each other directly. The idea is to create modules that represent one single entity, which in this case is playerStats. The module definition would look like this:

define([
    'angular',
    'components/playerStats/directives/playersListDirective',
    'components/playerStats/directives/playersDetailDirective',
    'domain/Players'
],  function(ng, playersListDirective, playersDetailDirective, Players) {
        'use strict';
        
        return ng.module('playerStatsModule', [])
                 .directive('playersList', playersListDirective)
                 .directive('playersDetail', playersDetailDirective) 
                 .service('Players', Players);
                 
    }
);

Notice that there's one file playerStatsModule.js which declares dependency on the directives and the service. Also, the name is to the directive here in the module definition. This approach is the flip side of the approach that is generally followed when defining directives. Generally one would create a module first and then use the module reference in their directive definition; but the approach that I mentioned above makes the code more cleaner. Here's how the definition of the playersList directive would look like:

define(function() {
    'use strict';
    
    return function () {
        return {
            restrict: 'AE',
            templateUrl: './components/playerStats/partials/playersList.html',
            scope: {
                onPlayerSelect: '&',
                players: '=',
                selectedPlayer: '='
            }
        };
    };
});

It returns a function and then in the module a name is assigned to the directive.

Application structure:

/app
  - app.js
  - main.js
  - bootstrap.js
  - index.html
  /components
      /auth
      /login
      /navbar
      /playerStats
           /directives
                - playersDetailsDirective.js
                - playersListDirective.js
           /partials
                - playersDetails.html
                - playersList.html
  /domain
       -  Players.js
       -  User.js
  /modules
        - authModule.js
        - loginModule.js
        - navbarModule.js
        - pagesModule.js
        - playerStatsModule.js
  /pages
      /home
          /controllers
               - playersListController.js
               - playersStatsController.js
          /partials
               - playersList.html
               - playersStats.html
      /login

Notice that the services responsible for sending requests to the server are listed under domain. The pages directory lists various pages in the application and the partials listed under each page contain references to these components. In this way, pages handle the application logic (events, querying the service, etc) and individual component directives handle rendering logic.

In app.js, a module for the application is created. This module will declare dependency on various other modules in the source code in addition to third party modules:

define([
    'angular',
    /*mock module*/
    'mockModule',
    'mockServices',
    /* user defined modules */
    'modules/authModule',
    'modules/loginModule',
    'modules/navbarModule',
    'modules/playerStatsModule',
    /* pages module */
    'modules/pagesModule',
    /* include vendor dependencies here */
    'angularCookies',
    'angularMessages',
    'uirouter',
    'lumx',
], function (ng) {
    'use strict';
    
    var app = ng.module('playersApp', [
        'ngCookies',
        'ui.router',
        'lumx',
        'mockModule',
        'authModule',
        'loginModule',
        'navbarModule',
        'playerStatsModule',
        'pagesModule'
    ]);
});

The main.js file declares the shim configuration (mentioned before) and bootstrap.js would bootstrap the application by calling angular.bootstrap on the document object.

Other Goodies:

I'm taking help from lumx to implement Material design, Angular UI router to define states/routes in the application, Angular Mocks to mock services and Gulp for build.

Pending:

Unit testing using Jasmine and Karma.
Structure styles (CSS/SCSS).
Refine Gulp build system.
CI/travis.yaml

You can clone the repository and see how the application is structured and how it is currently styled.


Comments

Popular posts from this blog

File upload and Progress events with HTML5 XmlHttpRequest Level 2

The XmlHttpRequest Level 2 specification adds several enhancements to the XmlHttpRequest object. Last week I had blogged about cross-origin-requests and how it is different from Flash\Silverlight's approach .  With Level 2 specification one can upload the file to the server by passing the file object to the send method. In this post I'll try to explore uploading file using XmlHttpRequest 2 in conjunction with the progress events. I'll also provide a description on the new HTML5 tag -  progress which can be updated while the file is being uploaded to the server. And of course, some ColdFusion code that will show how the file is accepted and stored on the server directory.

Server sent events with HTML5 and ColdFusion

There are several ways to interact with the server apart from the traditional request\response and refresh all protocol. They are polling, long polling, Ajax and Websockets ( pusherapp ). Of all these Ajax and Websockets have been very popular. There is another way to interact with the server such that the server can send notifications to the client using Server Sent Events (SSE) . SSE is a part of HTML5 spec:  http://dev.w3.org/html5/eventsource/

Adding beforeRender and afterRender functions to a Backbone View

I was working on a Backbone application that updated the DOM when a response was received from the server. In a Backbone View, the initialize method would perform some operations and then call the render method to update the view. This worked fine, however there was scenario where in I wanted to perform some tasks before and after rendering the view. This can be considered as firing an event before and after the function had completed its execution. I found a very simple way to do this with Underscore's wrap method.