Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS directive: put a call function in an attribute, without including another attribute

What I'm after

I would like to create a ngLoad directive for images on my webpage. This is my preferred markup:

<img ng-src="{{ src }}" ng-load="onLoad()">

What I have

JSFiddle

Right now, I have a imgLoad directive with ngLoad specified in the scope, like so:

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

app.directive('imgLoad', [function() {
    return {
        restrict: 'A',
        scope: {
            loadHandler: '&ngLoad'
        },
        link: function (scope, element, attr) {
            element.on('load', scope.loadHandler);
        }
    };
}]);

The resulting markup is:

<img ng-src="{{ src }}" img-load ng-load="onLoad()">

Edit: I previously assumed that the name of the directive (i.e. imgLoad) needed to be different from the name of my attribute (i.e. ngLoad). This is not the case. The solution is to name my directive ngLoad.

What needs to change

I want to get rid of the imgLoad attribute. I want ngLoad to work regardless of any other attributes.

What I've already seen

My implementation is based on:

  • angularjs directive call function specified in attribute and pass an argument to it
  • AngularJS - Image "onload" event
  • AngularJS: introduction to directives and $compile documentation

Any help is much appreciated!

like image 848
Tyler Eich Avatar asked Dec 31 '13 22:12

Tyler Eich


People also ask

What are angular attribute directives?

Angular attribute directives are a number of built-in directives that we can add to our HTML elements that give them a dynamic behavior. In summary, an attribute directive changes the appearance or behavior of a DOM element. There are three kinds of directives in Angular namely: Components - This is basically a directive with a template.

Why can't angular highlightdirective bind to a specific module?

Angular detects that you're trying to bind to something but it can't find this directive in the module's declarations array. After specifying HighlightDirective in the declarations array, Angular knows it can apply the directive to components declared in this module. To summarize, Angular found the myHighlight attribute on the <p> element.

What is the difference between import and input in angular?

The import statement specifies symbols from the Angular core: Directive provides the functionality of the @Directive decorator. ElementRef injects into the directive's constructor so the code can access the DOM element. Input allows data to flow from the binding expression into the directive.

What is the difference between component and structural directive in angular?

The Structural Directive’s name always starts with an asterisk (*) prefix, whereas Attribute Directive does not contain any prefix. The three most popular built-in Structural Directives Angular provides are NgIf, NgFor, and NgSwitch. Components are directives with templates.


Video Answer


1 Answers

Simple Solution Using Isolate Scope

Thanks to @smk for this answer

Give the directive and the scope property the same name.

app.directive('imgLoad', function() { // 'imgLoad'
    return {
        restrict: 'A',
        scope: {
            loadHandler: '&imgLoad' // 'imgLoad'
        },
        link: function (scope, element, attr) {
            element.on('load', scope.loadHandler);
        }
    };
});

HTML:

<img img-load="onLoad()">

JSFiddle • AngularJS Guide to Isolate Scopes

While this solution is practical for most situations, it prevents you from using another directive with an isolate scope on the same element. Which brings us to…

More Control Using $parse

Use $parse to process the attributes yourself. The effect will be the same, and there won't be any conflicts with isolate scopes.

app.directive('imgLoad', ['$parse', function($parse) { // Inject $parse
    return {
        restrict: 'A',
        link: function(scope, element, attr) {
            var loadHandler = $parse(attr.imgLoad); /* Parse value of
                                                       'imgLoad' attribute */
            element.on('load', function() {
                loadHandler(scope); /* Run the function returned by $parse.
                                       It needs the scope object
                                       to operate properly. */
            });
        }
    };
}]);

HTML (looks the same as before):

<img img-load="onLoad()">

JSFiddle • AngularJS $parse Documentation

Side Note: I didn't use ngLoad because Angular advises against it

like image 153
Tyler Eich Avatar answered Oct 06 '22 13:10

Tyler Eich