Let’s Make an AngularJS Custom Directive

Hello, this is Ohto from the Onsen UI Team.

Today, we are going to create an AngularJS custom directive. This is a simple directive that wraps ngInclude. If you are looking for the basics about AngularJS, this blog post would be more helpful for you.

If you are using Monaca, download this folder to import your project. Please click here to see how to import a project.

index.html

js/app.js

I will explain only the part of app.js which defines the directive. The following part defines the custom directive, ons-include, that is used in index.html.

The directive is dependent on the $compile service.

myApp.directive('onsInclude', function($compile)

Setting “replace : true” determines whether the current element is replaced by the directive. This thread elaborates on the details and provides examples for better understanding.

Setting “scope : false” has this directive share its scope with the parent scope. This plunker explains when the scope is false. Incidentally, setting no value in the scope will return a false value.

I am not going to cover the details today, but you can also generate child scopes that inherit their parent’s scope or isolate scopes. Creating these will allow you to control access from the outside to directive-provided method and variables.

Setting “restrict: ‘EA’” allows the setting of a directive inside an HTML tag either as E (element) or A (attribute).

In index.html, ons-include is set as E (element).

<ons-include page='templates/page1.html'></ons-include>

However, you can also set ons-include as A (attribute). The below code also works.

<div ons-include page='templates/page1.html'></div>

Setting a link option defines a function that will run when this directive is compiled, or an API that will be exposed. This directive’s scope is stored in $scope, and as is DOM in $element and attribute in $attrs.

link: function($scope, $element, $attrs) {
....
});

For cases where the page value has been already set as this directive’s attribute, enter that page value in $scope.onsIncludeCurrentPage. If the page value is not set, enter $scope.onsIncludeCurrentPage as defined in the parent scope. I will not explain about how to work around errors due to not having $scope.onsIncludeCurrentPage in this entry. Next, generate a DOM that includes ngInclude and pass $scope.onsIncludeCurrentPage to that ngInclude. Pass onsIncludeAnimation the CSS class (as defined in the parent scope), which will serve as the page transition animation. Lastly, replace it with the generated ngInclude DOM.

As a result, the below:

<ons-include page='templates/page1.html'></ons-include>

Will be compiled as follows:

The CSS class for the animation specified in the parent scope is included in onsIncludeAnimation. Also, the page specified in either “ons-include” or the parent scope is included in ng-include.

With the above code, you can create a directive simply to wrap ngInclude, gather data from the service, pass data from the controller to the directive, and modify the view. On the other hand, you can delegate to the directives for additional data and APIs from other controllers and services, by writing the below code:

Now, it’s not the controller but the ons-include directive that provides the page transition API, and also controls the CSS for animation, taking on more roles and responsibilities. On the other hand, the service simply has HTML page information defined by the app developer. The controller’s focus is only on its role of accessing the directive-provided API and notifying of data changes within the view.

This is how you can create your own custom HTML elements by using directives. Onsen UI also consists of various custom AngularJS directives. With the release of the latest version 1.0.3, Onsen UI offers an even more sophisticated design and improved usability.

Try the latest features of Onsen UI, and send us your feedback! We will incorporate your feedback to help improve the framework, and to create a more awesome UI in more intuitive environment.

That’s all for today. Thanks for reading!


Originally published at onsen.io on March 28, 2014.