EL MOJO
EL MOJO

Reputation: 793

Get Property Value From Parent Directive within Child Directive

I have two Angular directives, one nested inside the other as shown below.

HTML

<gss-response-group response-group-id="43" response-group-title="'Group Title'">
  <gss-response-option option-id="5" option-text="'Very Often'" option-value="5.00" options-inline="true" type="'radio'"></gss-response-option>
  <gss-response-option option-id="6" option-text="'Often'" option-value="4.00" options-inline="true" type="'radio'"></gss-response-option>
  <gss-response-option option-id="7" option-text="'Sometimes'" option-value="3.00" options-inline="true" type="'radio'"></gss-response-option>
  <gss-response-option option-id="8" option-text="'Rarely'" option-value="2.00" options-inline="true" type="'radio'"></gss-response-option>
  <gss-response-option option-id="9" option-text="'Never'" option-value="1.00" options-inline="true" type="'radio'"></gss-response-option>
</gss-response-group>

responseGroup.template.html

  <div class="gss-response-group">
    <label class="gss-response-group-title" ng-if="responseGroupTitle != null">{{responseGroupTitle}}</label>
    <placeholder></placeholder>
  </div>

responseOption.template.html

<div ng-class="{'gss-response-option': optionsInline}">
  <input class="gss-{{type}}-option" id="{{id}}" name="{{groupName}}" type="{{type}}" value="{{optionValue}}" />
  <label class="gss-option-text" for="{{id}}">{{optionText}}</label>
  <div class="gss-specifyanswer" ng-if="specify">
    <label class="gss-specifyanswer" ng-if="specifyText != null">{{specifyText}}</label>
    <textarea class="gss-specifyanswer" maxlength="5000" disabled></textarea>
  </div>
</div>

JavaScript

'use strict';

angular.module( 'gssApp', [ 'gss.directives' ] );

angular.module( 'gssApp' )

.controller( 'gssAppController', [

    '$scope',
    '$http',
    '$rootScope',

    function ( $scope, $http, $rootScope )
    {

    }] );

var directiveModule = angular.module( 'gss.directives', [] );

directiveModule.directive( 'gssResponseGroup', function ()
{
  return {
    restrict: 'E',
    transclude: true,
    replace: true,
    scope: {
      responseGroupTitle: '=',
      responseGroupId: '='
    },
    templateUrl: 'responseGroup.template.html',
    link: function ( scope, element, attrs, ctrl, transclude )
    {
      element.find( 'placeholder' ).replaceWith( transclude() );
    },
    controller: [

        '$scope',
        '$rootScope',
        '$element',
        '$attrs',

    function ( $scope, $rootScope, $element, $attrs )
    {

    }]
  };
} );

directiveModule.directive( 'gssResponseOption', function ()
{
  return {
    restrict: 'E',    
    transclude: true,
    replace: true,
    scope: {
      responseGroupId: '=',
      optionId: '=',
      optionText: '=',
      optionValue: '=',
      type: '=',
      optionsInline: '=',
      specify: '=',
      specifyText: '='      
    },
    templateUrl: 'responseOption.template.html',
    controller: [

        '$scope',
        '$rootScope',
        '$element',
        '$attrs',

    function ( $scope, $rootScope, $element, $attrs )
    {
      // HOW DO I GET THE PARENT DIRECTIVE'S SCOPE TO USE THE
      // responseGroupId FROM IT?
      $scope.id = 'rgID' + '_' + $scope.responseGroupId + '_' + $scope.optionId;
      $scope.groupName = 'rg' + '_' + $scope.responseGroupId;
    }]
  };
} );

I want the child directive to have access to the "response-group-id" field in the parent. How do I do this? I was able to get the value by having the parent directive be required by the child directive and then getting it within the "link" method of the child directive but by then it was too late to be applied to the child template.

Code in Plunker.

Also, if anyone could tell me why the CSS isn't being applied within my Plunker project, I'd appreciate it (though not a big deal).

Upvotes: 0

Views: 2129

Answers (2)

starchild
starchild

Reputation: 496

To share data between directives, it is recommended to define the shared data on the controller of the parent directive, and access it from the link function of the child directive (see last example "Creating Directives that Communicate" in angular Developer Guide).

So your parent directive's controller would look like:

function ( $scope, $rootScope, $element, $attrs )
{
  this.id = $scope.responseGroupId;
}]

And your child directive would look like:

directiveModule.directive( 'gssResponseOption', function ()
{
  return {
  ...
  require: '^gssResponseGroup',
  link: function(scope, element, attrs, gssResponseGroupCtrl) {
    scope.id = 'rgID' + '_' + gssResponseGroupCtrl.id + '_' + scope.optionId;
    scope.groupName = 'rg' + '_' + gssResponseGroupCtrl.id;
  }

Note that this solution will break if the responseGroupId is interpolated. If the value changes, it will not be reflected in the controller id property since it is only set once. Instead of the id property, the controller would have to define a getter method that always checks the latest value of $scope.responseGroupId.

Upvotes: 3

Mike Quinlan
Mike Quinlan

Reputation: 2882

Though I think you're making things a lot harder than they need to be, here's a solution:

<gss-response-group response-group-id="43">
  <gss-response-option response-group-id="responseGroupId"></gss-response-option>
</gss-response-group>

Then in your responseGroupOption directive:

return {
  // Other Logic...
  scope: {
    responseGroupId: '='
  }
};

Upvotes: 0

Related Questions