1

I'm trying to create a component that contains multiple child components. I'm creating a collection of directives that other developers on my team can use to create custom search forms. For example, they would create markup like:

<search-panel name="myCustomSearch">
    <search-field name="dates" type="dateRange"></search-field>
    <search-field name="categories" type="categorySelector" data="{{categories}}"></search-field>
</search-panel>

I have a search panel directive and several search field directives. The search panel acts as a container and the search fields each provides a specific type of field (date range, type ahead, category selector, etc). Each search field has a value property in it's scope and I am trying to figure out a way to have the parent search panel directive have a property in it's scope that contains a key, value collection of all of the child search fields.

I've got both directives rendering correctly, but I'm not sure how to either make the search-panel aware of/have access to all the child components.

4 Answers 4

2

You can require in search-field directive a search-panel controller using require:'^searchPanel'

Then in link function you'll have a link to that controller, so those directives could add themselves into some array (I assuemm each search field has its isolated scope):

link: function(scope, elem, attrs, spCtrl) {
  spCtrl.fields.push({name: attrs.name, scope: scope});
}

(ofcourse, you could add not whole scope, but some object, then watch for changes and update value field of that object.

Sign up to request clarification or add additional context in comments.

Comments

0

The basic idea here is to create a common controller between the two and link them up in the directive linking.

When you create a directive you can pass the controllers into the fourth parameter as such:

app.directive('myDirective', function(){
  return {
    scope: true,
    link: function postLink( scope, element, attrs, ctrls ){
      //check ctrls for common link
    }
  }
}

An excellent example created in the angularui/bootstrap project is the Tabs Directive which has a common controller linking them up as an example on where to get started.

Hope this helps.

Comments

0

There is a good stackoverflow answer here by Mark Rajcok:

AngularJS directive controllers requiring parent directive controllers?

with a link to this very clear jsFiddle: http://jsfiddle.net/mrajcok/StXFK/

<div ng-controller="MyCtrl">
    <div screen>
        <div component>
            <div widget>
                <button ng-click="widgetIt()">Woo Hoo</button>
            </div>
        </div>
    </div>
</div>

JavaScript is in the jsFiddle.

Comments

0

My implementation of composite component (multiple transcluding directives) is based on the following idea:

  • capture child component $transclude with one directive
  • output this child component with another directive

Live demo http://nickholub.github.io/angular-composite-component/#/

Demo source code https://github.com/nickholub/angular-composite-component

Directive source code https://github.com/nickholub/angular-composite-component/blob/master/app/directive/angular-composite-component.js

<div cs-composite>
    <div cs-section="header">
        Composite Component Header
    </div>
    <div cs-section="footer">
        Composite Component Footer
        <div>Random Value: {{randomValue}}</div>
        <div>Percentage: {{percentage}}%</div>
    </div>
</div>

Directive that captures content

.directive('csSection', function () {
    return {
      transclude: 'element',
      priority: 100,
      require: '^csComposite',
      link: function (scope, element, attrs, ctrl, $transclude) {
        var directiveTransclude = {
          id: attrs.csSection,
          transclude: $transclude,
          element: element
        };

        ctrl.registerTransclude(directiveTransclude);
      }
    };
  })

Directive that outputs content

.directive('csTransclude', function () {
    return {
      transclude: true,
      link: function (scope, element, attrs) {
        var id = attrs.csTransclude;
        var directiveTransclude = scope.transcludes[id];
        if (directiveTransclude) {
          var selectedScope = scope.$new();
          directiveTransclude.transclude(selectedScope, function (clone) {
            element.append(clone);
          });
        }
      }
    };
  })

Comments

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.