13

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:

Any help is much appreciated!

Community
  • 1
  • 1
Tyler Eich
  • 4,239
  • 3
  • 21
  • 45
  • 1
    http://jsfiddle.net/7NyTN/ doesnt this work? why 2 directives? – smk Dec 31 '13 at 23:04
  • @smk I think you answered my question. I had assumed the name of the directive needed to be different from the scope property. – Tyler Eich Jan 01 '14 at 00:28
  • So, this question doesn't make sense, given the OP assumptions. Might as well remove it. – Stewie Jan 01 '14 at 00:50
  • 1
    I still think the question is a good reference, especially for those just starting to write directives (like me). – Tyler Eich Jan 01 '14 at 01:55
  • 1
    I updated my original post to explain my assumptions. I would like @smk to put his comment into an answer. If that doesn't happen in a few days, I'll probably answer my own question, crediting him for his solution – Tyler Eich Jan 01 '14 at 04:03

1 Answers1

21

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()">

JSFiddleAngularJS 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()">

JSFiddleAngularJS $parse Documentation

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

Community
  • 1
  • 1
Tyler Eich
  • 4,239
  • 3
  • 21
  • 45