My name is Ismael Chang Ghalimi. I build the STOIC platform. I am a stoic, and this blog is my agora.

View meta-model

Following the MVC pattern, we’ve properly separated our record view’s View from its Model, and we’re linking the two through bindings from the View and through control flow statements from the Controller. But we went a step further by also defining a meta-model for the view itself.

The justification for it is the following: the record view’s job is to display a form for the record of an object, plus additional information such as workflow status and changes timeline. For the form part, fields can be organized across multiple sections, which themselves are displayed through multiple tabs. While our current record view only supports the canonical generation of a form based on the model of the record’s object, a future version will let users create their own custom forms for any object.

In such a context, we need a way to define the structure of a form, by nesting references to fields within sections and sections within tabs. Then, we need to generate a canonical form structure for objects that do not have any custom form, or dynamically lookup a pre-defined form structure. Finally, we need to merge this form structure with the record’s data, the object’s model, and the definition of all datatypes used by fields of the object (a field’s datatype defines its widget).

This is pretty much what we did yesterday. At first, I was expecting this project to take a few days. We would have to develop a form meta-model from scratch, then implement a fairly sophisticated template (the View) to merge data and meta-data about four different entities (form, record, object, datatype). Instead, we were done in about three hours, and all it took fit within less than 60 lines of code:

  • HTML template (less than 40 lines of code, widgets excluded)
  • Canonical form generator (less than 20 lines of code)
  • Canonical form meta-model (simple JSON dynamically populated by the form generator)

How come? AngularJS works. Plain and simple…

Adding classes to elements within an iterator

AngularJS offers support for powerful expressions within templates. Unfortunately, you cannot write a control flow statement in an expression (conditionals, loops, or throw). According to the documentation, “the reason behind this is core to the angular philosophy that application logic should be in controllers, not in the view. If you need a conditional, loop, or to throw from a view expression, delegate to a JavaScript method instead.”

This is a bit of a shame, especially when trying to add a class to specific elements within an iterator (loop, using ng-repeat), either the first one, the last one, or any element in the middle. This is especially frustrating since AngularJS conveniently provides special properties for it ($index, $first, $middle, $last). Separation of concerns should be a philosophy, not a religion, and many control flow statements really belong to the view, not to the controller.

In order to work around this problem, we just created the following helper function:

$scope.isOn = function(elementPosition, className) {
  return elementPosition ? className : null;
}

We added this function to our controller and invoked it from our templates like that:

class="{{isOn($first, 'active')}}"

This will add the active class to the first element within a list. Of course, the very same function can be used with $middle and $last as well. We implemented this helper function in order to activate the first tab of our record view now that we’re dynamically generating the record view’s structure based on a JSON definition (more on this later).

UPDATE: We just learned that ternary operators are supported in expressions. This was documented in this stackoverflow answer and we tested it within our code. It removes the need for the helper function we implemented, and makes the code a lot more readable:

ng:class="{true:'active', false:''}[$first]"

Don’t be shy

Yesterday was quite interesting. Ken and I struggled for about half of it trying to figure out how to access a custom element’s attribute from the linking function of an AngularJS directive. I spent another couple hours on it, then decided to seek some help and asked my very first question on stackoverflow. Within less than half an hour (on a Saturday), I had an answer (thank you Artem). This taught me an important lesson and gave me some valuable insight:

  • Lesson: don’t be shy and ask for help when you’re stuck
  • Insight: there is an active community supporting AngularJS today

Once I had my answer, things started to click, and I quickly implemented a few more features of the new record view. Quite frankly, compilation and linking with AngularJS is anything but simple, and one must read the documentation quite a few time before being able to use advanced functions such as $observe. But once you get it, it’s quite simply amazing.

After a few hours, the basic structure of the record view was implemented, using native directives such as ng-repeat to loop through the fields of a record’ object, ng-init to lookup a field’s datatype, ng-show to hide hidden fields, and ng-switch to dynamically select a widget based on a field’s datatype. Within less than an hour, the core structure of the record view was implemented, all within the HTML template, while a couple of custom directives were added to implement some widgets. As an added bonus, this makes the record view a bit more extensible than it used to be, with the ability to dynamically add new widgets (not just new datatypes).

As I write more and more code, a few things are becoming clear: with native jQuery, your HTML templates are tiny and most of your code ends up being written in JavaScript. With AngularJS, it’s the exact opposite. Also, because AngularJS is built on top of jQuery and relies on the DOM for manipulating templates (instead of strings), making shortcuts down to the jQuery level remains very natural, both from your HTML templates (when embedding jQuery plugins), and from the compile and link functions of your custom directives (when manipulating their DOM outputs). In other words, adopting AngularJS does not make you lose any of the jQuery goodness that you’ve learned to love. Instead, it just makes it better.

AngularJS directives

I just implemented my first AngularJS directive. To be perfectly honest, I was a bit scared at first, because of the complexity of the documentation. AngularJS is a very powerful framework, with tons of advanced features, and this can be a bit disconcerting initially. Nevertheless, after an hour of work, my first directive was working beautifully, allowing me to create my own HTML elements and attributes, without any server-side component.

Once again, the resulting code is absolutely beautiful. HTML looks like HTML, JavaScript looks like JavaScript, and bindings between the two are not only clear and simple, but they can be made bi-directional, which is amazingly powerful. Another interesting aspect is that the same directive can be invoked from an element, an attribute, a class, or a comment. This is illustrative of the main philosophy behind AngularJS, which is to give the developer full control over HTML.

Now, to be perfectly honest, such versatility also contributes to making the framework a bit intimating at first. The developers of AngularJS value simplicity as much as we do, and their framework is a perfect example of the cost that one has to pay for making simpler something that is inherently complex. Once you’ve gone over the fairly steep learning curve, you can use AngularJS to develop very sophisticated applications in a simple and elegant manner, with code that will be smaller and more readable than with any other tool. But you have to make this initial investment first, which might require some leap of faith.

Now, if you need help for making this leap of faith while you’re trying to decide which framework to use (Ember.js and Knockout are great alternatives), all you have to know is that what makes AngularJS unique and so powerful is that it’s essentially an HTML compiler running in the web browser. As such, and unlike other templating engines, it deals with the DOM instead of strings. While it makes it a bit harder to understand (and must have made it really tricky to implement), it’s also what contributes to making the code you write so clean and simple.

Beyond that, AngularJS also comes with solid libraries for internationalization and localization, form validation, and unit testing. Last but not least, it provides a very powerful debugging tool (Angular JS Batarang) built as an extension for Google Chrome.

So, to make a long story short, we’ve been converted!

What to see the results? Check stoic.com out!

AngularUI and Bootstrap integration

Now that we’ve decided to go with AngularJS for our new user interface framework, we can start re-implementing our record view and query builder. For this purpose, we will need a few widgets, which we will get from AngularUI and Bootstrap.

On that front, I am pleased to report that things are looking pretty good. After a couple hours of work, I implemented field documentation using Bootstrap Tooltips and field masks using AngularUI Mask, which itself is based on jQuery Masked Input.

For the former, all I had to do was to activate tooltips with this jQuery statement:

$("[rel=tooltip]").tooltip();

And for the latter, I added the following line to my controller:

angular.module('sutoiku', ['ui']);

Step by step, I am re-implementing all the features of the record view, and while I’m still finding my way around all the capabilities offered by AngularJS, my first impression is that the code I’m writing is a lot smaller, and a lot more readable. It will be interesting to see how much smaller it ends up being compared to the previous version. As a reminder, here are the features offered by the record view:

  • User-defined tabs
  • User-defined sections
  • User-configured columns
  • User-ordered fields
  • User-extensible input widgets (Check Box, Text Box, Text Area, etc.)
  • Field labels (displaying the name of the field)
  • Field placeholders (displaying some sample content)
  • Field data masks (for datatypes like phone number)
  • Field documentation (in a popup window)
  • Field highlighting (highlighting of the field being edited)
  • Editable fields (uneditable fields are disabled)
  • Hidden fields (invisible to the user but still present in the form’s data)
  • Informative fields (disabled and displayed on a separate tab)
  • Required fields (with asterisk next to the field’s label)
  • Calculated fields (with real-time calculation, if we can implement it)
  • Conditional fields (for which editable, hidden, and required are set by rules)
  • Error messages (for validation errors and missing required fields)
  • Prefixes and suffixes (for currency amounts, percentages, and quantities)
  • Field styles (for customizing the way fields display data)
  • Field icons (for displaying field details)
  • Field details (for displaying details of target records referenced in relations)
  • Dynamic lookups (for relationship fields)
  • Formatters (for displaying data)
  • Parsers (for gathering data)
  • Validators (for validation)
  • Buttons (save and cancel)

Love at first sight

I’m less than an hour into my first AngularJS + Bootstrap project, and I’m already in love.

I have done HTML development for 18 years now, and it always felt like some awkward gymnastics exercise. Anything a bit subtle required painful contorsions between HTML, JavaScript, and CSS. And when everything was said and done, the final code looked awful. Granted, I’m a rather mediocre developer, but I’m sure many excellent coders can relate.

From what I can tell, the combination of AngularJS and Bootstrap might put an end to my misery. The reason for it is pretty simple: by using directives to create new HTML syntax, AngularJS (unlike other frameworks or libraries) allows developers to do a lot more work at the HTML level, thereby reducing the need to jump back and forth between HTML and JavaScript. And by using Bootstrap for basic CSS and components, developers can get a first version of an application very quickly that looks great right out of the box, thereby removing the need to go down to the CSS level for quite a while, or — quite possibly — forever.

As a result, most of the work is done at the HTML level, with code that is both extremely terse and highly readable. But unlike the server-side templating languages that were popular a decade ago, AngularJS lets you cleanly separate models from views, while making their interactions dynamic. And whenever you need to write some JavaScript code to implement a behavior that is not supported by existing components, the resulting controller looks like plain old JavaScript code, without any of the DOM heritage that still pervades code written with jQuery directly. In other words, your HTML looks like HTML, your JavaScript looks like JavaScript, and your CSS is small (thanks to LESS), or simply non-existant.

While I still have a lot more work to do, I can already say with a high degree of confidence that the combination of AngularJS and Bootstrap is exactly what we’ve been looking for, and will make us a lot more productive than we’ve ever been with any other framework.

I’m impressed. I’m really, really impressed.