1

I am trying to create three different directives that need to communicate together, and this isn't really a problem but I would like to explore the possibility of using an isolate scope, or at least as small a scope as possible between them.

Because sharing directly on the controller scope is so discouraged, I enacted this to try and get around that. The only solution I've seen immediately is to make all three behaviors in the same single directive, so that they all use the same scope - but this is very messy.

This is an extremely slim example of how it works. The full code is very long and it's not useful without a lot of extra context. I'm trying to trim it down to just what I need help with.

1. Is there a better way to share these scope properties between the directives?

2. Can I do it using an isolate scope, to reduce the clutter and load on the controller?

3. The reason for sharing information is a bit hard to explain briefly.

directives

angular.module('app', [])
.directive('dataSourceUrl', ['$parse', function($parse) {
   return {
        restrict: 'A',
        priority: 10,
        link: function(scope, element, attributes) {
            var path = attributes.dataSourceUrl;
                
            angular.extend(scope.options, {
                /* more code */
            });
        }
   }
}])
.directive('dataSourceOptions', 
    ['$parse', function($parse) {
    return {
        restrict: 'A',
        priority: 9,
        link: function(scope, element, attributes) {
            var options = scope.$eval(attributes['dataSourceOptions']);
            
            angular.extend(scope.options, {
                /* more code */
            });
        }
    }
}])
.directive('dataSourceColumns', 
    ['$parse', function($parse) {
    return {
        restrict: 'A',
        priority: 9,
        link: function(scope, element, attributes) {
            var columns = scope.$eval(attributes.dataSourceColumns);
            
            angular.forEach(columns, function(value, key) {
                switch(value) {
                    case "Id":
                        scope.options.columns.push({ field: "Id" /* more code */ });
                        break;
                    case "Name":
                        scope.options.columns.push({ field: "Name" /* more code */ });
                        break;
                    /* more code */
                }
            });
        }
    }
}]);

notes

My experience with angular is minimal, I am very new. I have researched isolate scope extensively, but it is proving to be more difficult than I thought. My goal is to use these directives kind of like this ...

<div kendo-grid data-source-url="'path/to/data'" 
     data-source-options="options" 
     data-source-columns="['Id','Name','Abbreviation','Group']">
</div>
4
  • multiple isolate scoped directive on same html element do actually share their scopes. best way of sharing data depends on how the two directives are related. Commented Sep 9, 2014 at 16:47
  • And that is precisely what I am hoping for. I am just having a very hard time finding examples of it, and interpreting it. Commented Sep 9, 2014 at 16:48
  • you would need to read docs on angularjs scopes, nothing else can help. the topic is too deep to be explained here. sorry. Commented Sep 9, 2014 at 16:52
  • I have read that documentation dozens of times, and it is not helpful. Commented Sep 9, 2014 at 16:54

2 Answers 2

2

you can have multiple isolate scoped directive on same element. though as far as i remember, read it somewhere, that multiple isolate scoped directive do share the scopes.

you can read more about scopes here

regarding sharing the data between directives, are the directives independent or are they in parent-child relationship?

if parent child then use require property of directives. and pass data only to parent directive and access it in child directive.

if they are sibling or independent, pass data to each directive separately.

lets assume that dataSourceUrl display changes on basis of parameters in dataSourceOptions. then you can use require property.

.directive('dataSourceUrl', 
    ['$parse', function($parse) {
    return {
        restrict: 'A',
        require: 'dataSourceOptions'
        link: function(scope, iElement, iAttrs, ctrlOptions)
               {
                         //ctrlOption.showHeadeers or something
                }
Sign up to request clarification or add additional context in comments.

15 Comments

Can you elaborate on what you mean by "parent-child"? You mean does directive2 depend on directive1? I'm not sure how that terminology works in this context.
I am not certain how these would classify. Each directive represents one HTML attribute, basically. But all three of them together form the collective behavior.
in that case, I would define them not as 3 directives, but one directive with multiple parameters.
scope : { options: '=', url: '@', column: '=' } so you receive multiple options in single directive.
keep just one directive and remove plnkr.co/edit/5Xxv5nRdIWC6ixX6zGgL?p=preview
|
1

Here is the fiddle where two directive are integrated

http://jsfiddle.net/Wijmo/MTKp7/

and code is

angular.module("btst", []).
directive("btstAccordion", function () {
    return {
        restrict: "E",
        transclude: true,
        replace: true,
        scope: {},
        template:
            "<div class='accordion' ng-transclude></div>",
        link: function (scope, element, attrs) {

            // give this element a unique id
            var id = element.attr("id");
            if (!id) {
                id = "btst-acc" + scope.$id;
                element.attr("id", id);
            }

            // set data-parent on accordion-toggle elements
            var arr = element.find(".accordion-toggle");
            for (var i = 0; i < arr.length; i++) {
                $(arr[i]).attr("data-parent", "#" + id);
                $(arr[i]).attr("href", "#" + id + "collapse" + i);
            }
            arr = element.find(".accordion-body");
            $(arr[0]).addClass("in"); // expand first pane
            for (var i = 0; i < arr.length; i++) {
                $(arr[i]).attr("id", id + "collapse" + i);
            }
        },
        controller: function () {}
    };
}).
directive('btstPane', function () {
    return {
        require: "^btstAccordion",
        restrict: "E",
        transclude: true,
        replace: true,
        scope: {
            title: "@",
            category: "=",
            order: "="
        },
        template:
            "<div class='accordion-group' >" +
            "  <div class='accordion-heading'>" +
            "    <a class='accordion-toggle' data-toggle='collapse'> {{category.name}} - </a>" +

            "  </div>" +
            "<div class='accordion-body collapse'>" +
            "  <div class='accordion-inner' ng-transclude></div>" +
            "  </div>" +
            "</div>",
        link: function (scope, element, attrs) {
            scope.$watch("title", function () {
                // NOTE: this requires jQuery (jQLite won't do html)
                var hdr = element.find(".accordion-toggle");
                hdr.html(scope.title);
            });
        }
    };
})

and also you can see the accordion example from this js

https://github.com/angular-ui/bootstrap/blob/master/src/accordion/accordion.js

1 Comment

I am a little confused about how they are integrated. Don't misunderstand, I am very thankful for the help, I am just not sure how I'm supposed to interpret this. I'm not using template or transclude at all. They only seem to relate to each other in that they call DOM elements through jQuery.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.