February 2014
What are directives, and why should you care about them?
Directives are regularly described as the ability to teach HTML new tricks, but what the heck does that mean?
Let’s imagine a scenario where a directive can be helpful.
You have a contact form on your site where your users can submit their email and hit send. The problem is, your backend is really slow to respond, so users become impatient and press “submit” multiple times, causing multiple requests to be made [and spamming your email!].
Wouldn’t it be nice if the submit button became disabled after the form was submitted, and then re-enabled after the request was finished?
In this tutorial we’ll be building a basic directive to handle this scenario.
List of things you've entered:
Pretty cool, right?
Not only do we prevent double form submission, but we also provide some visual feedback to the user (changing “Save” to “Saving…”).
Now that we know what we’re building, let’s hop into it.
I’ve removed all unneccessary css styles and markup so that we’re just looking at the code necessary for the directive. Full source is available here
<form name="myForm">
: Form is not only a default HTML tag, but also a directive in AngularJS. By assigning a name to our form, we have access to myForm
from within our controller’s $scope. This gives us access to certain methods and properties, such as $valid to check for validity.
<input>
: let’s take a look at the input tag. Here we are binding the text field to newThing.content
, which will assign it to $scope.newThing.content
in our controller. This is the object that we will be submitting with our form.
<button>
: now for the fun stuff, the button. There are a few things to explain here before diving into the JavaScript.
Attribute | Description |
---|---|
ng-click="submitForm(newThing)" | This will call the submitForm() function in our controller when clicked, and pass in the newThing object, that we have altered within our form. |
loading-text="Saving..." | This is the text that will replace "Save" after the button is clicked. |
enable-button="myForm.$pristine" | This is passing in the state of the form to our directive. The method `$pristine` returns true if the user has not altered the form yet. |
submit-button | By adding this as an attribute to our button element, we are instantiating our submitButton directive. |
Now that we have taken a look at the HTML markup needed for our form, let’s move on to the JavaScript…
Here we are just creating the application called MyApp, and a basic controller. MyCtrl contains an array, listOfThings
, and the submitForm()
function that is called when pressing Save. I have added a 1.5 second timeout to simulate a slow response from a web server.
Code | Description |
---|---|
Creates the directive named submitButton. You probably noticed in our HTML that we added an attribute called submit-button to the element. Directives are automatically converted from hash-style in HTML, to camelCase in our JavaScript. ex: submit-button #=> submitButton |
|
States that this directive can only be added as an attribute on an HTML element. By default, all directives are restricted to attribute only. If you wanted to create a custom element like <submit-button></submit-button>, you would restrict to an element ('E'). | |
Sets the directive to have an isolated scope. This means that the directive has it's own $scope, and it will not have access to the properties/methods that are defined in MyCtrl. This is often considered to be a best practice, as the directive is not dependent on belonging to a specific controller. This also sets two variables within our directive. Let's look into what the @ and = signs mean, and how they were set.
|
|
The link function is where the magic happens. Here is where the logic of the directive is written. You have access to the $scope, element, and attributes (not shown here). | |
Here we are binding the click event to a function that will disable the button, and change the text to the loading-text value that we passed in earlier ('Saving...') | |
First we are grabbing the original button value, "Save", and storing it in the variable defaultSaveText. Next we are watching the value of enableButton, which is the form state. When the enableButton variable changes, we are enabling the form again by removing the disabled attribute, and resetting the text. |
That’s it! Hopefully this has given you an idea of how to contruct a basic directive. Directives can be used in many situations, and can really help to keep your code DRY.
If you’re looking for more in-depth information , please consult the official angular documentation. They have examples on the different capabilities of directives, such as using templates, custom DOM elements, and shared scopes.