All posts by Marco

I would like to use TypeScript @Decorators in my unit tests

Before being almost exclusively a frontend developer who only uses JavaScript on a daily basis, I have done quite a bit of Java development on frontend as well as on the backend side. When writing unit tests in Java, our typical unit tests looked like this:

@RunWith(MockitoJUnitRunner.class)
public class StatisticsContextControllerTest {

	@Spy
	@InjectMocks
	private StatisticsContextController beanToTest;
	
	@Mock
	private StatisticsContextBusinessBean statisticsContextBusinessBean;
	
	@Spy
	private StatisticsContextFilter filterSpy = new StatisticsContextFilter();
	
	@Before
	public void setup() {}
	
	@Test
	public void testDenyStatisticsContext() {
	  //
	}
}

This is a JUnit4 test class that is run with Mockito as a test runner. What makes Mockito so amazing is, that I as a developer don’t have to manually handle the mock classes anymore. Mockito does that for me.

In the above test class, Java annotations are used to mark certain properties in the test class as Mocks or Spies that are automatically used to be injected in the to be tested class. This class needs to be marked with the @InjectMocks annotation. Mockito automatically creates mock instances of all mocks, spies and the class that is to be tested. If the class that is to be tested has a property with a type that is the same as one of the mocks, the mock is assigned to this property upon creation of the class.

In the end I have clean code in the test class which doesn’t contain any boiler plate code to setup the test case. I only need to care about mock implementations or mock return values.

And I would really like to use something like this in my unit tests which I write in Typescript. But this is isn’t possible as far as I know unfortunately.

Why?

First, Typescript decorators are still marked as an experimental feature even if they are used extensively in an angular environment. You still have to manually activate them in tsconfig.json via “experimentalDecorators: true”.

Second, the current TypeScript decorators can ONLY be used in classes, such as class decorators or method decorators. But the major testing frameworks (Jasmine, Jest, Mocha) can’t be written as test classes as all of them use a functional approach to define test cases.

This is a typical Jest test case:

describe("MyService", () => {
  let service: myService;

  beforeEach(() => {
    service = new MyService();
  };

  it("should do something", () => {
    service.doSomething();
  });

});

describe(), beforeEach() and it() are “just” functions which are used to define a test suite. Every test case is “only” a function that is called by the testing framework. This means, you can’t decorate any member, variable or function inside the test case with decorators.

I have created quite a few tests in the last weeks and quickly the most tedious and boring thing to do was to define and create the mocks and let them be injected into the class to be tested.

This often looked like something like this:

describe('MyService', () => {
  const errorServiceMock = {
    log: jest.fn().mockName("errorService.log"),
    logError: jest.fn().mockName("errorService.logError")
  };
  let service: MyService;

  beforeEach(() => {
    service = new MyService(errorServiceMock as any);
    
    errorServiceMock.log.clearMock();
    errorServiceMock.logError.clearMock();
  });

This can get quite messy when you use the angular dependency injection extensively and have to declare and define every mock yourself … again and again in every test suite. My test suites often had more lines of code for initializing the mocks than the real test cases.

Jest (the testing framework) has a feature called “module mocking” which mocks a complete module that is imported into your production code, but this doesn’t work for the angular dependency injection as you need objects/class instances to inject into your production code.

After a while I had enough, I didn’t care about the implementation details of the injected classes in my test suite for “myService” and I didn’t want to declare the same mocks again and again. They have their own test suites, I just want to test “myService” and ideally only use mocks to inject into “myService” so I can only define mock implementations and mock return values which are specific to this single test suite.

So, I created a function which did most of the heavy lifting to initialize an object so that it had the same (mocked) public properties as a class that can be parametrized:

describe('MyService', () => {
  const errorServiceMock = mockClass<ErrorService>(ErrorService);

  let service: MyService;

  beforeEach(() => {
    service = new MyService(errorServiceMock);
    
    clearMocks();  // mocks are reused between test cases and suites and need to be cleared
  });

This looked already much better and is type safe too as errorServiceMock has the same members as the ErrorService class. So it can be used as a (injection) parameter for the service class that I want to test.

But as I now had a pure function to define a mock “class” it would be neat to use this function as a decorator. A decorator is just this: a function that is called at a certain point in the lifetime of a class.

Possible solution

In the end I only came to this solution:

describe('MyService', () => {
  class Mocks extends MockHolder {
    @Mock(ErrorService)
    errorService: ErrorService;
  }

  const mocks = initMocks("mocks", Mocks);

  let service: MyService;

  beforeEach(() => {
    service = new MyService(mocks.errorService);
    clearMocks();  // mocks are reused between test cases and suites and need to be cleared
  });

Its just an empty class with some properties that are marked as mocks. The class needs to be initialized at one point and just holds the mocks. The class itself is only a holder of instances of mocks.

This is not much better than using mockClass() directly (see above) and I have not introduced it in my test suites. I’m no real expert in the Javascript testing community and have no clues if any testing framework has discussed plans so that developers are able to use classes as test suites. But it would be nice.

Download

My mockClass() function and the decorator can be found as a gist on github.

How to conditionally set the root page of an Ionic app

The rootpage of an Ionic app is the first page that is displayed after the root component (normally app.component.ts). The rootpage is the start of the app navigation and is always the first element in the navigation stack. It can be navigated to like this after the app is initialized and running:

@Component(....)
class MyComponent {
  constructor(navCtrl: NavController){}

  gotoRoot() {
    this.navCtrl.setRoot(MyAwesomePage); //sets a new rootPage and navigates there
  }

  poptoRoot() {
    this.navCtrl.popToRoot();  //return to the existing rootPage and navigate there
  }
}

The first rootpage upon app initialization is set in the AppComponent that belongs to the (root) AppModule. In the docs its only mentioned that you define the rootPage as a quasi static property of the AppComponent like this example taken directly from the Ionic documentation:

@Component(
  template: `<ion-nav [root]="rootPage"></ion-nav>`
})
class MyApp {
  // set the rootPage to the first page we want displayed
  public rootPage: any = StartPage;

  constructor(){
  }
}

Its not mentioned anywhere, but you can also define rootPage lazy and conditionally, like f.i. when you have a local database and want to first initialize the database driver and look into it to check if the user is already logged in or not. Depending on the result you want to display a LoginPage as the rootpage or your normal standard page for users.

That is done almost always asynchronous so you can’t define the rootPage in the constructor of your AppComponent because you don’t know it yet.

In this case you can leave the rootPage uninitialized and just set it later. Ionic automatically grabs any changes and navigates to the rootPage:

@Component(
  template: `<ion-nav [root]="rootPage"></ion-nav>`
})
class MyApp {
  // don't set the rootPage initially to anything
  public rootPage: any

  constructor(private userService: UserService){
    this.userService.initDatabaseAndUser().subscribe(user => {
      if (user.isLoggedIn) {
        this.rootPage = StartPage;
      } else {
        this.rootPage = LoginPage;
      }
    }
  }
}

How to implement custom page transitions in an Ionic app

Ionic is a fantastic framework to write your own apps. It is based on Cordova and angular and enables you to quickly write good looking apps without too much effort.

Depending on the platform you use to start your app Ionic even comes with pre-defined page transitions to animate the navigation of one page to another. The standard page transition on iOS is a swipe from left or right. It looks like this:




The documentation for page transitions in Ionic however is quite confusing and as a beginner it took some time to understand what transitions are there and which should be used. The official documentation contains a page for the NativePageTransitions module, however I advise you not to use that. Not only that it hasn’t received any updates for a long time, but to do the animations the modules takes a screenshot of the starting and the landing page and is animating the two images. This seems a weird way to do that and the amount of open issues while not issues get closed speaks for itself.

What you should use, is an integrated feature of the Ionic NavController class which you already use to navigate between your pages. This feature is enabled by default (depending on the platform) but it can be configured with your navigation call too:


this.navCtrl.push(MyPageComponent, null, {animate: true, animation: "transition"});  

With “animate: true” you turn on the animation (which is the standard setting) and “animation: transition” sets the animation to use to animate the page transition. Its a string and “transition” means to use the standard transition depending on the current platform. When you want to use the iOS transition on an android platform you can initiate the navigation like this:


this.navCtrl.push(MyPageComponent, null, {animate: true, animation: "transition-ios"});  

There are no other built-in transitions you can use (like slide-down, slide-up or scale-out) and I could find absolutely no official documentation how to implement a custom transition. However, there is a quasi-official way to implement your own transitions. Continue reading How to implement custom page transitions in an Ionic app

Implementing your own JSF tabview component without Primefaces

At my current company we are finally transitioning away from our well-aged Primefaces 3.0 jsf library and have implemented our own (composite) components for all use cases where we used primefaces thus far. As I learned a few things while implementing the components, I thought I could share it with others as good tutorials for composite components are quite rare.

Our composite component which we will be developing here is a tabview component just like the one you see on this screenshot of primefaces showcase. The tabview needs to render 1-n different tabs which the user can switch through freely with a click to the tab header. It’s a standard widget found in every operating system and many widget frameworks.

We will develop it based on twitter bootstrap markup and you can use it without any additional client javascript, you don’t even need the bootstrap.js as the switching of tabs is entirely done on the server side (we are talkng about JSF here!). The main advantages of it over the primefaces tabview are that you have learned something about jsf and that you can freely change the html markup as you need it. You can use any CSS styling framework you like.

The component should work with every JSF 2.x version.

Download

You can download the complete source code in my tabview github repository. You have to copy the templates and classes to your project manually. Don’t forget to adjust the package name of the class and the component name inside the class. If you have any question or suggestion just leave a comment.

Continue reading Implementing your own JSF tabview component without Primefaces

Creating open source code is helping me as a developer

When creating the github project and transferring the code for jsf-updates-angular I realized that opening up my code to the public, is helping me being a developer.

While creating the company internal code that jsf-updates-angular is based on, it was done as a part of a bigger code base. It was only a small part in a test branch. I did not really pay attentention to implement it in the most clean way. I mean … it was not bad code. But it was embedded and not meant to be used as a standalone library. It used jQuery, naturally, because jQuery is part of this project. It was a part of an existing module which was easy because it was already there.

jsf-updates-angular (jua) does not really need jQuery. When I would try to, I could do the DOM work on my own. Currently, even the released version of jua is using jQuery. I would only need to ready some articles to make myself familiar with the original browser API to the DOM. That can’t be that hard.

Ripping the code out and releasing it as a standalone module already gave me a new look onto my code. I already have tweaked it and thought about how others will likely use it. The code is now better than before. I did not think about this while writing this code in my company because … no one will take the file and use it somewhere else. No need to optimize it. Its just there.

But while releasing it, I looked on my code with other eyes. Maybe I saw it like I was an external code reviewer. Maybe I saw it as I would see it when I was the customer.

My company will benefit when I release open source software, because I’m learning.

And the next version of jua will not need jQuery.

JSF-updates-angular – How to use angularJS directives to replace JSF components

Writing JSF components is hard and complicated. No one in their right mind writes them. Except when you are a framework developer.

My team is struggling for some time now with Primefaces and its (natural) limitations where one cannot simply change the HTML output to the designers need. So, I spent some days this fall, to try to replace PrimeFaces components with an angular solution, so that PrimeFaces can be completely removed from the application and all components like dialogs or growls are replaced with angular directives.

I didn’t want to use AngularFaces as its trying to put too much magic into the application (for my personal taste). Its very interesting on paper, but when you use it, it seems that every single developer needs to understand exactly both lifecycles of JSF and angularJS and how both frameworks are working. This seems to be a challenge for every decent sized team.

Luckily, the XML parser of JSF leaves HTML tags it does not know of (aka: angularJS directives) alone and just outputs them in the rendered HTML. In a way, that works like the passthrough attributes in JSF 2.2.

As I wanted to use angularJS only as a “widget factory” in a JSF application, I had to solve only a short list of problems:

  • adding the ng-app attribute to the h:body tag is not possible when not using JSF 2.2, Solution: manual bootstrapping like described in angularjs documentation or wrapping your JSF template with a div and the ng-app attribute.
  • inform angularJS about DOM changes after a JSF AJAX request
  • implement a solution so that directives can make JSF AJAX requests, which is not possible out of the box as they can’t have a JSF ID in JSF versions < 2.2

Besides the first, the last two problems were the challenge.

Inform angularJS about DOM changes after a JSF AJAX request

When you load angularJS on page load in a JSF page, its working as expected: its doing its thing and enhances the DOM according to the registered directives. If you don’t use any AJAX requests at all, you are basically done.

The challenge with AJAX requests is, that angularJS needs to be informed about those changes, as they happen outside of an angularJS digest but can contain new DOM nodes with angularJS directives or are destroying/changing existing directives. AngularFaces solved it in a brute-force-like-way: the angularJS app will be completely destroyed and recreated after every JSF AJAX request. But as I only wanted to use directives, that seemed a little harsh for me.

So, after a little experimenting I’m presenting you:

JSF-Updates-Angular (or short: JUA).

Its a (very small) library to update angularJS after every JSF AJAX request:

  • adds 2 event listeners to the JSF JS library for the ajaxComplete and ajaxSuccess events
  • when ajaxComplete event happens, the DOM nodes that are updated by JSF are still unchanged. JUA will iterate through them, searching for nodes with a scope or isolate scope and call the $destroy method on those scopes. Destroying of scopes is done by angularJS itself.
  • when ajaxSuccess event happens, the DOM nodes that are updated by JSF are successfully updated and this library will compile them via angularJS $compile service.

The result is that even DOM nodes which are updated via JSF AJAX requests are enhanced by angularJS directives.

The current state of JUA is not production ready. It was only tested on a few developer machines in a Mojarra JSF 2.1.7 environment (JBoss 7.1.1.). But as I don’t see any JSF dependencies, it should work with any JSF version, provided the JSF AJAX event listener callback interface was not changed.

Trigger JSF AJAX requests inside of directives

When not using JSF 2.2 angularJS directives (aka HTML tags) can’t have JSF IDs and therefore can’t be the source of an JSF AJAX request. But even with JSF 2.2 or when you use a JSF component as a source, you have to build the requests yourself, which is … not so easy.

I made a short-cut here and am using the great OmniFaces library by balusC. With OmniFaces you have a o:commandScript JSF component which registers a global Javascript function to trigger a JSF request. The request can even send a payload with it (PrimeFaces has a similar component). When a angularJS directive needs to send AJAX requests to a managed bean, I’m just using a commandScript call, instead of inventing the wheel again. Works quite nice.

<tabview on-tab-change="makeTabActive">
	<h:panelGroup id="tabs">
		<tab id="detailTab" title="#{msgs.auftrag}" active="#{bean.detailTabActive">
			<h:form id="form">							 
				<o:commandScript name="makeTabActive"
				                 render=":tabs"
				                 execute="@this"
				                 action="#{bean.onTabChangeMethod()}" />
				<h:outputText value="Detail Tab Content" />
			</h:form>
		</tab>
		...
	</h:panelGroup>
</tabview>

(tabView and tab are angularJS element directives)

Tips

Use OmniFaces. Really, this library is great!

Re-implement your application in angularJS instead of JSF.

Execute javascript after AJAX request is complete

As pure JSF doesn’t have an easy way (is ANYTHING easy in JSF?) to execute Javascript after a JSF AJAX request, you can use OmniFaces Ajax.oncomplete() for this. Or (if you want) use the onComplete/onCompleteEvent function of JUA which guarentees that your callback listener is called AFTER angularJS was updated:

<h:commandLink value="Do Ajax stuff" action="#{bean.method()">
    <f:ajax update="@form" execute="@this" 
            onevent="jua.onCompleteEvent(myDialog.show)" />
</h:commandLink>

Register global function in your directives to call them outside of angularJS digest

My dialog directive – which will be replacing the primefaces dialog component – registers a global javascript function for every dialog name, so that it just can be used like the primefaces dialog. Call dialog.show() anywhere (even in click handlers of JSF components) to show the dialog and dialog.hide() to close it. For developers who don’t know anything about the implementation details, the new dialog behaves just like the PrimeFaces dialog.

$window[scope.dialog] = {
	show: function () {
		$window.jua.ensureExecutionAfterAjaxRequest(function () {
			$scope.apply(function () {
				addOverlay();
				scope.open = true;
			});
		});
	},
	hide: function () {
		hide();
	}
};

(this code is run inside an angularJS directive)

Make use of OmniFaces library components

Use o:messages of OmniFaces to output JSF messages to mimic the PrimeFaces growl component. With o:messages you can control the HTML output of messages and can give an angularJS directive all needed parameters to mimic a growl message.

<messages sticky="true"
	          life="20000"
	          show-detail="trur"
	          show-summary="true">
	<h:panelGroup id="messages">
		<o:messages var="message" showSummary="true" showDetail="true">
			<message summary="#{message.summary}" detail="#{message.detail}"
			         severity="#{message.severity}"></message>
		</o:messages>
	</h:panelGroup>
</messages>

(messages and message are angularJS element directives)

Datatable with fully dynamic columns in angularJS

First: there is a plunkr example for the following code examples.

While doing some testing for a possible new project which we want to do in angularJS I discovered that its quite hard to implement a datatable which should have fully dynamic columns which can be reordered and toggled to display or not.

Many datatable implementations have either hard-coded columns which you can’t change at all or you can’t change the order of the columns in which they should be rendered. ngTable does it like that for instance.

So, I spent a rainy sunday afternoon to implement my own version and after much poking around and some frustrating moments, I finally got it.

The first hurdle I had to take was, that angularJS can’t handle directives that have a <tr> or <td> element as the root element of the directive. There is an issue for this where its explained that these elements need to be handled special, which jQuery does, but jqLite in angularJS does not. There is a pull request for this too, but its not accepted yet.

After discovering that, I wrote a little helper function to create the elements like this:

function createTDElement() {
	var table = angular.element('<table><tr><td></td></tr></table>');
	return table.find('td');
}

The next problem I had was to implement the full dynamic columns which should be customizable from an angular controller. I didn’t want just define a hard-coded table with some columns in a html file and manipulate the DOM elements after they were created by angularJS. I wanted to do it the angular way.

I decided that every column needs to have its own directive where the output inside the cells is defined. These directives are not known to the wrapper directive, but are part of the customization inside the controller, so the wrapper is fully generalized and can be used with any type and any number of columns. The wrapper directive adds additional elements into the DOM in the $compile phase of angularJS which have the correct column directives set to them dynamically.

The html in the view looks like this:

<table border="1">
    <tr ng-repeat="item in items" item="item" columns="columns">
</table>

Inside the controller you have something like this:

function myController($scope) {
   $scope.items = [//someitems];

  $scope.columns = [{
    id: "column2",
    title: "Manufacturer",
    directive: "secondcolumn",
    visible: true
  }, {
    id: "column1",
    title: "ID",
    directive: "firstcolumn",
    visible: true
  }, {
    id: "column3",
    title: "Country",
    directive: "thirdcolumn",
    visible: false
  }, ];
}

So in this case the table should render with 2 columns: column2 first, then column1 and column3 should not be visible. The property “columnDirective” is used to find out the directive that renders this columns html output.

$scope.items is the data object, that you want to display in the table.

The important parts of the column directive, which does all the magic, look like this:

function createTDElement(directive) {
	var table = angular.element('<table><tr><td ' + directive + '></td></tr></table>');
	return table.find('td');
}
app.directive('item', function($compile) {
  function createTDElement(directive) {
    var table = angular.element('<table><tr><td ' + directive + '></td></tr></table>');
    return table.find('td');
  }

  function render(element, scope) {
    var column, html, i;
    for (i = 0; i < scope.columns.length; i++) {
      column = scope.columns[i];
      if (column.visible) {
        html = $compile(createTDElement(column.directive))(scope);
        element.append(html);
      }
    }

  }

  return {
    restrict: 'A',
    scope: {
      item: "=",
      columns: "="
    },
    controller: function($scope, $element) {
      $scope.$watch(function() {
        return $scope.columns;
      }, function(newvalue, oldvalue) {
        if (newvalue !== oldvalue) {
          $element.children().remove();
          render($element, $scope);
          $compile($element.contents())($scope);
        }
      }, true);
    },
    compile: function() {
      return function(scope, element) {
        render(element, scope);
      }

    }
  };

});

(The implementations for the columns are missing here).

And thats it.

I created a plunkr which has an working example for this so you can play around with it.

Tell me if you know some way to implement this easier.

How to handle angularJS promises in jasmine unit tests

When developing unit tests in an angularJS app, you eventually stumble about a problem that can be quite frustrating to handle it in a clean und concisive way: promises.

Lets have a look at an example method in a controller:

$scope.method = function() {
    someService.loadData().then(function(data) {
       $scope.data = data;
    }
}

This method is calling loadData() on an angularJS service which is returning a promise, which could be resolved only after a $http call is finished.

How to handle that in a unit test?

Clearly, you should mock someService, thats easy. But what to do with the promise? In my first couple of tests, I tried to reimplement promises somewhat and ended with ugly constructs like this:

someServiceMock = {
    loadData: jasmine.createSpy().andCallFake(function() {
        then: jasmine.createSpy()
    }
}

This way I had to call the resolve or reject functions in my test manually, like so:

it('should be a lot easier', function() {
   controllerScope.someMethod();

   resolveFunction = someServiceMock.loadData().then.mostRecentCall.args[0];
   resolveFunction('resolveData');

   expect(controllerScope.data).toBe('resolveData');
});

That worked, but its ugly as hell.

So, after some studying with google I just refactored my tests with a much simpler solution, which uses the original $q service to resolve promises and calls the appropriate function arguments automatically.

Defining the mock service changes a bit and needs to be in an inject function as $q service is needed:

beforeEach(function() {
    inject(function(_someService_, _$q_, _$rootScope) {
        var deferred = _$q_.defer();
    
        someService = _someService;
        rootScope = _$rootScope_;
    
        deferred.resolve('resolveData');
        spyOn(someService, 'loadData').andReturn(deferred.promise);
    })
})

it('is now a lot easier', function() {
   controllerScope.someMethod();
   rootScope.$apply();
   expect(controllerScope.data).toBe('resolveData');
}

The loadData() spy is now always returning a resolved promise.

Of course, you can (and maybe should be) resolve the promise in the test itself if the data is different when you have more than one test.

The catch is though, that you need to call rootScope.$apply() method manually in your test as promises only get resolved during a angular $digest phase. After this method is finished, all promises are really resolved and you can test for the expected outcome.

Mocking $window in an angularJS test

When trying to mock the angularJS internal $window factory, I recently stumbled about an error message when running the test:

TypeError: Cannot read property 'userAgent' of undefined
	    at $SnifferProvider.$get (C:/projects/hwa-mobile/src/main/external-libs/angular.js:8327:72)
	    at Object.invoke (C:/projects/hwa-mobile/src/main/external-libs/angular.js:2864:28)
	    at C:/projects/hwa-mobile/src/main/external-libs/angular.js:2702:37
	    at getService (C:/projects/hwa-mobile/src/main/external-libs/angular.js:2824:39)
	    at Object.invoke (C:/projects/hwa-mobile/src/main/external-libs/angular.js:2842:13)
	    at C:/projects/hwa-mobile/src/main/external-libs/angular.js:2702:37
	    at getService (C:/projects/hwa-mobile/src/main/external-libs/angular.js:2824:39)
	    at Object.invoke (C:/projects/hwa-mobile/src/main/external-libs/angular.js:2842:13)
	    at C:/projects/hwa-mobile/src/main/external-libs/angular.js:2702:37
	    at getService (C:/projects/hwa-mobile/src/main/external-libs/angular.js:2824:39)

The test looked something like this:

describe('myService', function () {
	beforeEach(function () {
		module("myModule",function ($provide) {
			$provide.factory('$window', function () {
				return jasmine.createSpy('$windowmock');
			});
		});
		....
	});

	it('should do something', function () {
		...
	});
});

Apparently angularJS itself tries to read the userAgent even when running inside a mocked environment.

The solution was quite easy:

describe('myService', function () {
	beforeEach(function () {
		module("myModule",function ($provide) {
			$provide.factory('$window', function () {
				var windowmock = jasmine.createSpy('$window);
				windowmock.navigator = window.navigator;
				return windowmock;
			});
		});
		....
	});

	it('should do something', function () {
		...
	});
});

The navigator property of the jasmine mock object will be the original navigator property of the original window object. Smells a bit, but works.

How to structure large angularJS applications

I did it all wrong in my first angularJS application. Oh I did it really wrong!

The structure of my first angular project looked something like this:

Root folder
js
controllers
Somecontroller.js
Anothercontroller.js
controller.js
directives
Firstdirective.js
SecondDirective.js
directives.js
services
AService.js
BService.js
services.js
app.js
index.html
partial1.html
partial2.html

So, all controllers were going to “controllers” folder, services into “services” folder and partials lived directly next to full html files. When we started to have more than 10 directives and 5 services the problems with this approach were really backfiring:

  • it was not easily visible what files were depending on what other files
  • refactorings were thus quite hard
  • reusing features in other code/applications was hard as the structure didn’t allow to group files of a single feature together
  • it was hard for new developers to understand the flow of the application
  • it was hard to extend the application so that it not only consisted of one (single page) application but of two applications that shared some features

Since then I tried a few different approaches and while experimenting with ngStart as a skeleton for new angular projects I’m now settled with an approach I want to use in all my next projects.

What I came up with, is an approach that groups features into angularJS modules. The main advantages is that the code structure is based on features of the application and every feature is defining its own angularJS module. The angular root module then is the glue and binds all modules together.

The structure of ngStart looks like this:

Root folder
modules
contact
contact.js
contact.html
ContactController.js
ContactService.js
about
about.js
about.html
AboutController.js
app.js
index.html

The main idea is that every folder under “modules” is by definition an angular module. The module is always declared in a javascript file that is named like the folder (“about” -> about.js) and is the name of the module too.

Each angular module can use the full list of angular features. It can have its own angular.config() phase function, can declare its own routes and can have its own list of dependencies.

modules

To refactor a certain feature you now know exactly where to begin and what files are directly dependent on each other when they implement a single feature. You can move modules around and even move them out of the your first single-page app, make another app and declare a dependency on the module to reuse your code.

In a small and trivial example the advantages of this approach are not easily visible, but as soon as a team of developers works together on an application it will grow very fast.

In enterprise applications there is usually a software architect who defines a structure which the team has to follow. Programming languages in the backend also have features to structure code in packages or modules and import it. Javascript doesn’t. And often times the software architect doesn’t care about javascript or the frontend at all. And frontend developers tend to not care about it neither as tools were missing in the past and there wasn’t really a need for it when writing jquery scripts.

But as frontend engineers or frontend developers of today, you should care! AngularJS is great. But angularJS applications will face the same problems as every other application that begins to grow. And your structure should make it easy to grow and adapt. You should care from the beginning!