Manipulating the DOM
In the previous recipe, you built a directive that didn't care what it was attached to, what it was in, or what was around it. Directives exist for you to program the DOM, and the equivalent of the last recipe is to instantiate a variable. In this recipe, you will actually implement some logic.
How to do it…
The far more common use case of directives is to create them as an HTML element attribute (this is the default behavior for restrict
). As you can imagine, this allows us to decorate existing material in the DOM, as follows:
(app.js) angular.module('myApp', []) .directive('counter', function () { return { restrict: 'A', link: function (scope, el, attrs) { // read element attribute if it exists var incr = parseInt(attrs.incr || 1) , val = 0; // define callback for vanilla DOM click event el.bind('click', function () { el.html(val += incr); }); } }; });
This directive can then be used on a <button>
element as follows:
(index.html) <div ng-app="myApp"> <button counter></button> <button counter incr="5"></button> </div>
Tip
JSFiddle: http://jsfiddle.net/msfrisbie/knk5znke/
How it works…
AngularJS includes a subset of jQuery (dubbed jqLite) that lets you use a core toolset to modify the DOM. Here, your directive is attached to a singular element that the directive sees in its linking function as the element parameter. You are able to define your DOM modification logic here, which includes initial element modification and the setup of events.
In this recipe, you are consuming a static attribute value incr
inside the link
function as well as invoking several jqLite methods on the element. The element parameter provided to you is already packaged as a jqLite object, so you are free to inspect and modify it at your will. In this example, you are manually increasing the integer value of a counter, the result of which is inserted as text inside the button.
There's more…
Here, it's important to note that you will never need to modify the DOM in your controller, whether it is a directive controller or a general application controller. Because AngularJS and JavaScript are very flexible languages, it's possible to contort them to perform DOM manipulation. However, managing the DOM transformation out of place causes an undesirable dependency between the controller and the DOM (they should be totally decoupled) as well as makes testing more difficult. Thus, a well-formed AngularJS application will never modify the DOM in controllers. Directives are tailor-made to layer and group DOM modification tasks, and you should have no trouble using them as such.
Additionally, it's worth mentioning that the attrs
object is read-only, and you cannot set attributes through this channel. It's still possible to modify attributes using the element attribute, but state variables for elements can be much more elegantly implemented, which will be discussed in a later recipe.
See also
- In this recipe, you saw the
link
function used for the first time in a fairly rudimentary fashion. The next recipe, Linking directives, goes into further detail. - The Isolate scope recipe goes over the writable DOM element attributes that can be used as state variables.