ACA Blog

ACA Blog


June 2019
M T W T F S S
« May    
 12
3456789
10111213141516
17181920212223
24252627282930

Categories


Interfacing in AngularJS

Robin Van PraetRobin Van Praet

Angular

At ACA IT-Solutions we have been creating modular applications for some years using OSGi. Every project gives us the opportunity to reflect and improve our modular designs. One of our latest improvements is the introduction of an API at a higher level, for an entire sub-domain or bounded context. Other bounded contexts may only use this API to interact with it. For Java code, this is easily achieved, on AngularJS side lays the challenge.

Modular AngularJS code

An AngularJS application is generally one big collection of js-files containing AngularJS modules. During previous projects we already worked on the requirement to split these in different modules, enabling to split the UI code in different modules . A generic UI manager was introduced, which could fetch a list of all js-files for every UI module in our OSGi application and as such load AngularJS modules for every bounded context that was deployed in the OSGi environment.

The next step in this process is to split our AngularJS code in an interface and implementation bundle. This way the implementation can change and other bounded contexts can still interact with it (as long as the API did not break).

Introducing Interfaces in AngularJS

There is no out of the box support in AngularJS to create interfaces of Services, Controllers, Directives, … It does however have a concept of decorators. Let’s use this to achieve our goal.

Services

To create an interface for a service, define your service in the API bundle as you would for every other service. It may include some very simple implementation code if wanted. It should not depend on any code from the UI implementation bundle, just like creating interfaces in an API bundle in Java code…

As you can see here, the interface has one method called getServiceValue. If you would not deploy an implementation for this interface, calling getServiceValue will throw an exception. This will ensure that an implementation is available. Note that we are not really creating an interface here. It is actually just a Service containing methods that should be available to other bounded contexts. When you need to change these methods, it indicates that you are updating or even breaking the interface, therefore the API to other bounded contexts. This triggers to think about impact and semantic versioning.

Now let’s implement it in the UI bundle:

We are using the decorator function on $provide here. This will hook into the provider of Angular. The value that is returned will be the actual implementation, it can include ‘private’ methods or methods only to be used in the current bounded context. You could just as easily return a complete new implementation with totally different methods. Of course, this is not what we want, as we want to keep the implementation in line with the ‘interface’. It is just like providing an implementation for it, so we decorate the MyInterface service and replace the getServiceValue method with a real method.

In the other bounded context’s UI bundle we can now inject the MyInterface service and by that actually use the implementation.

Note: It is not required to provide an array with the parameter names and the function with the actual parameters. You can just as easily only provide the function to the decorator method. The array is only used to support minification of the code.

Directives

As directives are created at the time of use, we cannot just simply change the instance of the decorator, as there may be more than one instance at the time.

To create an interface for a directive, we want to provide only information that is of importance to the user of the API. We do not care about a template, template-url, controller or link function. The user only needs to know if the directive is an element or attribute, what parameters are available, which parent controller is required, … etc… Therefore we define the directive as follows:

As you can see this directive will do nothing when used.
Let’s provide an implementation:

Notice what we are decorating. We are decorating the definition of the Directive and not an instance of the Directive…. which results in myDirectiveDirective. It is perfectly possible in Angular to have multiple definitions of directives with the same name. We will actually get an array of directives as our delegate value. In this example, I’m sure we will only have one, so I gave that one a template. When the directive is now used, it will replace itself by the provided div.

Soon we noticed that many of our Directives use a Controller or link function. While we can provide the controller and link code in the implementation the actual behaviour was not what we expected. The link code did not always run when expected. Returning to the AngularJS documentation it became clear that the decorator function should only be used for Services. Not for specialized objects like Decorators. So:

Do not decorate Directives!!

We will create our directives directly in the API bundle. To keep the ‘implementation’ inside of implementation bundle, as much as possible, we will follow these guidelines:

Our Directives will generally look like this:

Controllers 

Why would you interface Controllers? These are actually implementation logic. You should be writing Directives to share UI code between bounded contexts and as such, you eliminate the need of interfaces Controllers.

Conclusion

Using the approach described above, we are now able to have both an API UI bundle and an implementing UI bundle for every bounded context in our OSGi application. This enables us to independently version the API and implementation bundles of a bounded context, making it easier for different teams to work on different bounded contexts and to manage the impact on each others development cycle.

 

 

Blog written by Robin Van Praet

robin
Solution Engineer at ACA IT-Solutions

Interested in joining our team?

Interested in meeting one of our team members? Interested in joining our team?
We are always looking for new motivated professionals to join the ACA team!
Have a look at our new ACA job website: http://www.aca-it.be/jobs

we-are-hiring

Leave a Reply

avatar
  Subscribe  
Notify of