7

I was wondering, if it is possible, to extend Angular's input directive? I want to attach some listeners to all input fields on a page. I think you can decorate existing modules with $provide.decorate, but I have no idea how to do this with a directive (and more precisely the input directive).

So, can anyone push me in the right direction? Some examples?

EDIT

Here is my directive that I have so far:

angular.module('onFocusBlur'). directive('onFocusBlur', ["$rootScope", function($rootScope) { return { restrict: "A", link: function(scope, elem, attrs) { elem.bind('focus',function() { scope.$apply(function() { $rootScope[attrs.onFocusBlur] = true; }); }); elem.bind('blur',function() { scope.$apply(function() { $rootScope[attrs.onFocusBlur] = false; }); }); } }; }]); 

In my view, I can add this to an input field like this:

<input type="email" ng-model="email" on-focus-blur="repositionNavBar"> 

The downside is, that for every input field, I have to attach this listener manually in my code. Therefore, it would be useful, to alter the existing input directive, to include this listeners.

5
  • what type of listeners your are talking?Can you please elaborate.CommentedMar 12, 2014 at 13:11
  • possible duplicate of Extending Angular DirectiveCommentedMar 12, 2014 at 13:17
  • I added some code with my existing directive
    – 23tux
    CommentedMar 12, 2014 at 13:17
  • thx for you comments. @KhanhTO but, does this overwrite the existing input directive?
    – 23tux
    CommentedMar 12, 2014 at 13:27
  • @23tux Have a look at my answer for the correct way of decorating the built-in input directive on an app-wide level, without the need to add behaviour through secondary directives.
    – user1364910
    CommentedJul 23, 2014 at 8:50

3 Answers 3

18

Here's a short gist of how you could decorate the built in Angular input directive, with $provide.decorator as you yourself suggested.

app.config(function ($provide) { // Suffix is "Directive" for decorating directives. // $delegate refers to the original directive definition. $provide.decorator('inputDirective', function ($delegate) { // When decorating a directive, $delegate is an array containing // all of the directives of the same name. // We're interested in the first in this case. var directive = $delegate[0]; // Store a reference to the original directive linking function. var link = directive.link; // Hook into the compile phase of the directive. directive.compile = function () { // The function returned by compile is your new link function. // Or 'postLink', to be exact. return function (scope, el, attrs) { // Run the original link function. link.apply(this, arguments); // Your new listener function function listener (e) { console.log(e); } // Set up your listener(s). el.bind('blur', listener); el.bind('focus', listener); }; }; // Return the decorated original ($delegate). return $delegate; }); }); 

Benefits of this approach, as I see it:

  1. It's more DRY than adding another directive to augment behaviour.
  2. It is an actual extension of third-party behaviour.
  3. For the most part, you don't need to know about the internal implementation of the directive (or service, for that matter) that you are decorating.

Here's a jsBin: http://jsbin.com/yafecinu/2/edit

I'd recommend you take a look at this article, that goes in-depth on decorating directives. The article covers extending not just linking phases, but controllers and pre-linking DOM manipulation aswell. A very good read!

4
  • This is the way to go but since Angular 1.3 you need to use pre link: var link = directive.link.pre;
    – Scraph
    CommentedNov 19, 2015 at 14:13
  • I ran into an issue using angular-bootstrap 1.1.1, with datepickers and I applied a custom decorator using this code. Instead of saving/calling the old pre-link function, I think a better solution would be to use the old compile function. It fixed my issues anyway.CommentedFeb 1, 2016 at 18:07
  • @JosephHelfert That wholly depends on how far you want to deviate from the original directive. If it's something simple, you can probably go with link/controller. If you need more fine-grain control, then using the old compile function works just dandy!
    – user1364910
    CommentedFeb 3, 2016 at 7:17
  • @KasperLewau Can you show an example of how to do this with the ng-submit directive?
    – theB3RV
    CommentedNov 30, 2016 at 21:10
3

See answer to this question. They talk about a couple different options to extend a directive from using $provide to making a directive with the same name.

Also, this link explains a few techniques (under "Extending Directives"): https://github.com/angular/angular.js/wiki/Understanding-Directives

    1

    You can easily extend any directive - including the input directive. Here is a quick example of adding a class to a directive.

    1
    • 9
      You are not extending anything, you are adding a seperate directive. Effectively creating the code OP is trying to avoid.CommentedMar 12, 2014 at 13:27

    Start asking to get answers

    Find the answer to your question by asking.

    Ask question

    Explore related questions

    See similar questions with these tags.