Using AngularJS directives to simplify the DIV hell

Using bootstrap to build a prototype for a web app is really handy. Everything gets a decent look pretty fast. This applies greatly if you are  are not in a web design phase, just want to deal with the proof of concept or want to lay the interface and components without worrying with the design and layout details.

My current web app project has many editing panels like this:

image

In these panels several features of bootstrap are used: panels, forms and accordion.

And it gets pretty messy very fast:

 
<div id="bl-mytemplates-editor" class="panel-group">
<div class="panel panel-default">
<div class="panel-heading"><a href="#bl-mytemplates-editor-properties" data-toggle="collapse" data-parent="bl-mytemplates-editor">Template Properties</a></div>
<div id="bl-mytemplates-editor-properties" class="panel-collapse collapse">
<div class="panel-body form-horizontal">
<div class="form-group form-group-sm row">
<label class="control-label col-sm-4"><span>Name</span></label>
<div class="col-sm-8">
<input type="text" class="form-control input-sm" placeholder="name" data-ng-model="templateData.name" />
</div>
</div>
<div class="form-group form-group-sm row">
<label class="control-label col-sm-4"><span>Width</span></label>
<div class="col-sm-8">
<input type="number" class="form-control input-sm" placeholder="width" data-ng-model="templateData.width" />
</div>
</div>
<div class="form-group form-group-sm row">
<label class="control-label col-sm-4"><span>Height</span></label>
<div class="col-sm-8">
<input type="number" class="form-control input-sm" placeholder="height" data-ng-model="templateData.height" />
</div>
</div>
<div class="form-group form-group-sm row">
<label class="control-label col-sm-4"><span>Margin</span></label>
<div class="col-sm-8">
<input type="number" class="form-control input-sm" placeholder="margin" data-ng-model="templateData.margin" />
</div>
</div>
<div class="form-group form-group-sm row">
<label class="control-label col-sm-4"><span>Border</span></label>
<div class="col-sm-8">
<input type="number" class="form-control input-sm" placeholder="border" data-ng-model="templateData.border" />
</div>
</div>
<div class="form-group form-group-sm row">
<label class="control-label col-sm-4"><span>Back</span></label>
<div class="col-sm-8">
<input type="color" class="form-control input-sm" placeholder="background color" data-ng-model="templateData.backgroundColor" />
</div>
</div>
</div>
</div>
</div>
</div>
 

I see three problems in here:

  • Verbosity. Copy/paste eases that code production but It is difficult to find the changing bits.
  • Readability. For someone that did not produce that code or did it some time ago, it has a very low readability.
  • Maintainability. It very difficult to make changes, mainly because it involves making the same change in many, many places. This is mainly the WET problem.

The solution is to make it DRY programming using AngularJS element directives.

<div id="bl-mytemplates-editor" class="panel-group" style="width:274px;">

<form-panel id="bl-mytemplates-editor" data-header="Template Properties">
<form-item data-label="Name">
<input type="text" class="form-control input-sm" placeholder="name" data-ng-model="templateData.name" />
</form-item>
<form-item data-label="Width">
<input type="number" class="form-control input-sm" placeholder="width" data-ng-model="templateData.width" />
</form-item>
<form-item data-label="Height">
<input type="number" class="form-control input-sm" placeholder="height" data-ng-model="templateData.height" />
</form-item>
<form-item data-label="Margin">
<input type="number" class="form-control input-sm" placeholder="margin" data-ng-model="templateData.margin" />
</form-item>
<form-item data-label="Border">
<input type="number" class="form-control input-sm" placeholder="border" data-ng-model="templateData.border" />
</form-item>
</form-panel>
</div>

The directives are the “new” HTML elements one can see in the above code: <form-panel> and <form-item>. In this case the purpose was not to make directives that can be used in different projects as pre-made components. That would require that each directive allowed for some level of customization, augmenting the complexity of its usage.

For prototyping, this solution provides a a simple usage by mainly concentrating the code on only one place. Two, in fact, the files “formpanel.html” and “formitem.html”. These serve as templates for the two new directives. The complementary files “formpanel.js” and “formitem.js” define the directives and basic parameters needed for customizing each use of each directive.

Here is a plunker with these files:

The directives define some properties in the “scope” that make the bridge between the directive customization and the use of that customization. Like the “id” and “header” parameter here:

<form-panel id="bl-mytemplates-editor" data-header="Template Properties">

is mapped to “id” and “header” properties:

scope: { id: '@', header: '@' }

These are used in the template:

<a href="#{{id}}-items" data-toggle="collapse" data-parent="{{id}}">{{header}}</a>

 

Have fun!

Leave a Reply

Your email address will not be published. Required fields are marked *