【问题标题】:Get Property Value From Parent Directive within Child Directive从子指令中的父指令获取属性值
【发布时间】:2014-05-02 21:18:43
【问题描述】:

我有两个 Angular 指令,一个嵌套在另一个内部,如下所示。

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;
    }]
  };
} );

我希望子指令能够访问父指令中的“response-group-id”字段。我该怎么做呢?通过让子指令需要父指令,然后在子指令的“链接”方法中获取它,我能够获得该值,但到那时应用到子模板为时已晚。

Code in Plunker.

另外,如果有人能告诉我为什么我的 Plunker 项目中没有应用 CSS,我将不胜感激(虽然没什么大不了的)。

【问题讨论】:

  • ... 为什么需要内部指令?您不能将输入定义存储在一个对象中,然后使用 ng-repeat 对其进行迭代吗?
  • 如果你必须知道,应该有一个 $parent 对象附加到你的范围
  • 我需要内部指令用于其他目的。这只是一个精简的示例,只是为了解决我遇到的问题的核心。
  • 你愿意详细说明我应该把 $parent 对象放在哪里吗?我已经在孩子内部尝试过 $scope.$parent 但它没有返回父指令。

标签: angularjs angularjs-directive angularjs-scope


【解决方案1】:

为了在指令之间共享数据,建议在父指令的控制器上定义共享数据,并从子指令的链接函数中访问它(参见angular Developer Guide中的最后一个示例“创建通信的指令”) )。

所以你的父指令的控制器看起来像:

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

你的子指令看起来像:

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;
  }

请注意,如果插入 responseGroupId,此解决方案将中断。如果值发生变化,它不会反映在控制器id 属性中,因为它只设置了一次。控制器必须定义一个始终检查 $scope.responseGroupId 的最新值的 getter 方法,而不是 id 属性。

【讨论】:

  • 我试过了,我能够将 responseGroupId 放入子指令中。然而,当“link”方法运行时,它已经使用它的模板“渲染”了子指令。因此,此时在孩子身上设置 responseGroupId 对我没有帮助。它需要在子指令初始化之前设置。你认为提高父指令的优先级可以解决这个问题吗?
  • 我认为更改指令的优先级不会有任何效果。
  • 实际上有两个链接功能,一个'pre'和一个'post'链接。 link: function 语法定义了 'post' 链接方法。你可以试试link: { pre: function(... }。这应该会导致在渲染指令之前调用该方法,但我不知道它是否足够早解决您的新问题。
  • 我以前没有遇到过,但我怀疑这是一个时间问题,孩子试图在它被正确嵌入到 DOM 之前进行渲染。尝试如上所述将 gssResponseGroup 链接函数更改为预链接,以便在调用子项的链接方法之前调用它。
  • 一般来说,设置指令的顺序是:(1)控制器; (2) 预链接; (三)设立子女; (4) 后链接。但是,如果有需要加载 html 模板的子指令,它们的设置可能会发生在父指令的 post-link 之后。
【解决方案2】:

虽然我认为你让事情变得比他们需要的要困难得多,但这里有一个解决方案:

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

然后在你的responseGroupOption 指令中:

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

【讨论】:

    猜你喜欢
    • 2015-09-24
    • 2015-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-27
    • 1970-01-01
    相关资源
    最近更新 更多