Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases now! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Learning Ionic

You're reading from   Learning Ionic Discover a simpler approach to modern mobile application development with Ionic framework and learn how to create elegant hybrid apps with HTML5 and AngularJS

Arrow left icon
Product type Paperback
Published in Jul 2015
Publisher
ISBN-13 9781783552603
Length 388 pages
Edition 1st Edition
Languages
Tools
Arrow right icon
Author (1):
Arrow left icon
Arvind Ravulavaru Arvind Ravulavaru
Author Profile Icon Arvind Ravulavaru
Arvind Ravulavaru
Arrow right icon
View More author details
Toc

Table of Contents (12) Chapters Close

Preface 1. Ionic – Powered by AngularJS FREE CHAPTER 2. Welcome to Ionic 3. Ionic CSS Components and Navigation 4. Ionic and SCSS 5. Ionic Directives and Services 6. Building a Bookstore App 7. Cordova and ngCordova 8. Building a Messaging App 9. Releasing the Ionic App A. Additional Topics and Tips Index

AngularJS directives

Quoting from the AngularJS documentation.

"At a high level, directives are markers on a DOM element (such as an attribute, element name, comment or CSS class) that tell AngularJS's HTML compiler ($compile) to attach a specified behavior to that DOM element or even transform the DOM element and its children."

This is a very useful feature when you want to abstract out the common functionality on your web page. This is similar to what AngularJS has done with its directives, such as the following ones:

  • ng-app: This initializes a new default AngularJS module when no value is passed to it; otherwise, it initializes the named module
  • ng-model: This maps the input element's value to the current scope
  • ng-show: This shows the DOM element when the expression passed to ng-show is true
  • ng-hide: This hides the DOM element when the expression passed to ng-hide is true
  • ng-repeat: This iterates the current tag and all its children based on the expression passed to ng-repeat

Referring to the Search App, which we built earlier, imagine that there are multiple pages in your web application that need this search form. The expected end result is pretty much the same across all pages.

So, instead of replicating the controller and the HTML template where needed, we would abstract this functionality into a custom directive.

You can initialize a new directive on a DOM element by referring to it using an attribute notation, such as <div my-search></div>, or you can create your own tag/element, such as <my-search></my-search>.

This would enable us to write the search functionality only once but use it many times. AngularJS takes care of initializing the directive when it comes into view and destroying the directive when it goes away from the view. Pretty nifty, right?

We will update our Search App by creating a new custom directive called my-search. The sole functionality of this directive would be to render a textbox and a button. When the user clicks on the Search button, we will fetch the results and display them below the search form.

So, let's get started.

As with any AngularJS component, the directives are also bound to a module. In our case, we already have a searchApp module. We will bind a new directive to this module:

searchApp.directive('mySearch', [function () {
   return {
          template : 'This is Search template',
          restrict: 'E',
          link: function (scope, iElement, iAttrs) {

          }
   };
}]);

The directive is named mySearch in camel case. AngularJS will take care of matching this directive with my-search when used in HTML. We will set a sample text to the template property. We will restrict the directive to be used as an element (E).

Note

Other values that you can restrict in an AngularJS directive are A (attribute), C (class), and M (comment). You can also allow the directive to use all four (ACEM) formats.

We have created a link method. This method is invoked whenever the directive comes into view. This method has three arguments injected to it, which are as follows:

  • scope: This refers to the scope in which this tag prevails in the DOM. For example, it could be inside AppCtrl or even directly inside rootScope (ng-app).
  • iElement: This is the DOM node object of the element on which the directive is present.
  • iAttrs: These are the attributes present on the current element.

In our directive, we would not be using iAttrs, as we do not have any attributes on our my-search tag.

In complex directives, it is a best practice to abstract your directive template to another file and then refer it in the directive using the templateUrl property. We will do the same in our directive too.

You can create a new file named directive.html in the same folder as index.html and add the following content:

<form>
    <label>Search : </label>
    <input type="text" name="query" ng-model="query" required>
    <input type="button" ng-disabled="!query" value="Search" ng-click="search()">
</form>

<div ng-repeat="res in results">
    <h2>{{res.heading}}</h2>
    <span>{{res.summary}}</span>
    <a ng-href="{{res.link}}">{{res.linkText}}</a>
</div>

In simple terms, we have removed all the markup in the index.html related to the search and placed it here.

Now, we will register a listener for the click event on the button inside the directive. The updated directive will look like this:

searchApp.directive('mySearch', [function() {
        return {
            templateUrl: './directive.html',
            restrict: 'E',
            link: function postLink(scope, iElement, iAttrs) {
                scope.search = function() {
                      var q = {
                          query : scope.query
                      };

                    // Interact with the factory (next step)
                }
            }
        };
    }])

As you can see from the preceding lines of code, the scope.search method is executed when the click event on the button is fired and scope.query returns the value of the textbox. This is quite similar to what we did in the controller.

Now, when a user clicks on the Search button after entering some text, we will call getResults method from ResultsFactory. Then, once the results are back, we will bind them to the results property on scope.

The completed directive will look like this:

searchApp.directive('mySearch', ['ResultsFactory', function(ResultsFactory) {
        return {
            templateUrl: './directive.html',
            restrict: 'E',
            link: function postLink(scope, iElement, iAttrs) {
                scope.search = function() {
                      var q = {
                          query : scope.query
                      };

                    ResultsFactory.getResults(q).then(function(response){
                      scope.results = response.data.results;
                    });
                }
            }
        };
    }])

With this, we can update our index.html to this:

<html ng-app="searchApp">
<head>
   <script src="angular.min.js" type="text/JavaScript"></script>
   <script src="app.js" type="text/JavaScript"></script>
</head>
<body>
   <my-search></my-search>
</body>
</html>

We can update our app.js to this:

var searchApp = angular.module('searchApp', []);

searchApp.factory('ResultsFactory', ['$http', function($http){

return {
 
   getResults : function(query){
         return $http.post('/getResults', query);
       }

};


}]);


searchApp.directive('mySearch', ['ResultsFactory', function(ResultsFactory) {
        return {
            templateUrl: './directive.html',
            restrict: 'E',
            link: function postLink(scope, iElement, iAttrs) {
                scope.search = function() {
                      var q = {
                          query : scope.query
                      };

                    ResultsFactory.getResults(q).then(function(response){
                      scope.results = response.data.results;
                    });
                }
            }
        };
    }]);

Quite simple, yet powerful!

Now, you can start sprinkling the <my-search></my-search> tag wherever you need a search bar.

You can take this directive to another level, where you can pass in an attribute named results-target to it. This would essentially be an ID of an element on the page. So, instead of showing the results below the search bar always, you can show the results inside the target provided.

Note

AngularJS comes with a lightweight version of jQuery named jqLite. jqLite does not support selector lookup. You need to add jQuery before AngularJS for AngularJS to use jQuery instead of jqLite. You can read more about jqLite at https://docs.angularJS.org/api/ng/function/angular.element.

This very feature makes AngularJS directives a perfect solution for reusable components when dealing with DOM.

So, if you want to add a new navigation bar to your Ionic app, all you need to do is throw in an ion-nav-bar tag, such as the following one, one your page:

<ion-nav-bar class="bar-positive">
  <ion-nav-back-button>
  </ion-nav-back-button>
</ion-nav-bar> 

Then, things will fall in place.

We went through the pain of understanding a custom directive so that you could easily relate to Ionic components that are built using AngularJS directives.

You have been reading a chapter from
Learning Ionic
Published in: Jul 2015
Publisher:
ISBN-13: 9781783552603
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime