Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sharing common code between directives

I'm working on the core of an angular project, and want to keep behaviors as separate as possible for the sake of reuse across multiple components. An example might be using the 'iScroll' library to pull-to-refresh some content. Currently, I'm running into problems because many of these behaviors require their own scope. I thought maybe wrapping up the behaviors in a service might be the way to go, but I haven't really seen many examples of that kind of thing. So I'm wondering if that's even the right way to go. Here's a very, very simple jsfiddle example:

http://jsfiddle.net/S7kC7/

var controls = angular.module('controls', []);
controls.service('ScrollingBehavior', function () {
    this.link = function ($scope, $element) {
        $element.addClass('scrolling');
    }
});

controls.directive('scrolling', ['ScrollingBehavior', function (ScrollingBehavior) {
    //pretend that this has its own individual scope
    return {
        restrict: 'A',
        link: function ($scope, $element) {
            console.log("Linking scrolling");
            ScrollingBehavior.link($scope, $element);
        }
    }
}]);

controls.directive('panel', ['ScrollingBehavior', function (ScrollingBehavior) {
    return {
        restrict: 'E',
        transclude: true,
        replace: true,
        template: '<div ng-transclude></div>',
        //pretend that this has its own individual scope
        link: function ($scope, $element) {
            console.log("Linking panel");
            ScrollingBehavior.link($scope, $element);
        }
    }
}]);

The idea is that I'd expose certain expected methods (i.e. "link", "controller") that could be used in the other directives that require those behaviors or features. Since the scope is an object and passed by reference, it could hook in just like if the code was just copied/pasted.

Are there problems about doing it this way? Can services be considered something to serve a sort of "mix-in"? Again, I'm only asking because I've not seen really any examples of something like this.

[note: I'm not sure, but maybe this belongs on the code review site?]

like image 214
Stephen Avatar asked Feb 14 '14 22:02

Stephen


1 Answers

I believe the 'angular' way to do this is to create a scrollingBehavior directive and tack that on to your other directives, nesting as necessary.

[Edit] Updated jsfiddle and example code with isolate scopes.

http://jsfiddle.net/8dYYk/

<div scrolling-with-scrolling-behavior>This should have a scroll bar</div>
<div scrolling><div scrolling-behavior>This should have a scroll bar</div></div>
<panel scrolling-behavior>This should also have a scroll bar</panel>


controls.directive('scrollingBehavior', function () {
    return {
        restrict: 'A',
        scope: { 'behavior': '=' },
        link: function ($scope, $element) {
            $element.addClass('scrolling');
        }
    }
});

controls.directive('scrolling', function () {
    //pretend that this has its own individual scope
    return {
        restrict: 'AE',
        scope: { 'otherThing': '=' },
        link: function ($scope, $element) {
            console.log("Linking scrolling");
        }
    }
});

controls.directive('scrollingWithScrollingBehavior', function () {
    return {
        restrict: 'A',
        transclude: true,
        scope: { 'behavior': '=' },
        template: '<div scrolling-behavior><div scrolling ng-transclude></div><div>'
    }
});
like image 108
Craig Squire Avatar answered Nov 12 '22 18:11

Craig Squire