在指令中嵌套指令时为什么绑定会丢失?

时间:2016-02-23 12:16:19

标签: angularjs angularjs-directive angularjs-scope angularjs-ng-repeat

问题

在另一个指令中使用我的指令会导致某些绑定丢失,特别是在ng-repeat用法中。

该指令在我的应用程序的许多方面都使用而没有问题。它呈现一个输入列表,从父模板传递给它的范围,如下所示:

<filter-header filters="filters"></filter-header>

工作情景

我在整个应用程序中使用了以下场景,并且迄今未遇到任何问题。

  • $routeProvider使用WebAPI调用控制器来解析过滤器列表
  • controller将列表分配给自己的范围,如下所示:$scope.filters = filters
  • 模板使用filter-header元素并将其范围内的过滤器传递给指令,如下所示:<filter-header filters="filters"></filter-header>
  • filter-header指令然后使用ng-repeat呈现过滤器而没有问题。过滤器集合的每个项目中都有$$hashKey,表示绑定的存在。

失败的情景

在以下场景中,绑定似乎丢失,ng-repeat无法呈现任何内容。

  • $routeProvider使用WebAPI调用控制器来解析过滤器列表
  • controller将列表分配给自己的范围,如下所示:$scope.filters = filters
  • 模板使用新的元素指令,通过属性将其范围内的过滤器分配给新指令。
  • 指令的模板使用filter-header元素并将其范围内的过滤器传递给指令,如下所示:<filter-header filters="filters"></filter-header>
  • filter-header指令然后 FAILS TO 使用ng-repeat渲染过滤器。 $$hashKey 出现在过滤器集合的任何项目中。

令人讨厌的是,我无法在Plunker中复制这个......

怪异

该指令还传递了另一个项目集合columns="columns"(可在下面的代码中看到)。列正确绑定并在其自己的ng-repeat中呈现。我无法看到Columns与Filters有何不同,因为两者的使用方式几乎完全相同。

更深入......

我一直在调试这个过程。 filters对象成功地一直到最终范围。如果我在最终指令中将过滤器的内容输出到屏幕,使用{{ filters }}我可以按预期看到所有过滤器。但是,在我的ng-repeat开始的下一行中,不会迭代过滤器。

为了确定它不是导致问题的列表,我使用了一个已经使用上述工作方案工作的列表,而ng-repeat在这里没有呈现。

要确定这不是我的指令导致问题的代码,我将其转换为控制器并直接路由到它(跳过嵌套指令),如上面提到的工作场景和ng-repeat现在有效。

使用$log检查列表,我注意到一个区别。在工作方案中,所有列表都包含列表中每个项目的$$hashKey属性。在失败的情况下,列表中的所有项目都缺少$$hashKey。这似乎表明绑定因某种原因而丢失。

有人可以用我的方式告诉我错误吗?我在使用中可以看到的唯一真正的区别是我在将对象传递给使用它的指令之前将对象传递给中间人指令。奇怪的是,在同一个指令中,另一个列表以非常相似的方式使用,并且它在ng-repeat内呈现没有问题,并且它的所有项目都具有{{ 1}}附加属性。

代码

涉及很多代码,所以我会尝试挑选相关部分。

RouteProvider

$$hashKey

EditAuditForm控制器

$routeProvider.when('/Pride/Admin/AuditForms/:id', {
    templateUrl: '/Templates/Admin/editAuditForm.html',
    controller: 'editAuditFormController',
    resolve: {
        sectionFilters: function (auditFormSectionRepository) {
            return auditFormSectionRepository.getFilters().$promise;
        },
        sectionColumns: function (auditFormSectionRepository) {
            return auditFormSectionRepository.getColumns().$promise;
        }
    }
});

EditAuditForm模板

prideModule.controller("editAuditFormController", function ($scope, sectionFilters, sectionColumns) {

    $scope.sectionFilters = sectionFilters;
    $scope.sectionColumns = sectionColumns;
});

AuditAdminSections指令

<audit-admin-sections audit-form="auditForm" section-filters="sectionFilters" section-columns="sectionColumns" show-deleted="false"></audit-admin-sections>

AuditFormSections模板

prideModule.directive('auditAdminSections', function ($log) {
    return {
        restrict: 'E',
        templateUrl: 'templates/admin/auditFormSections.html',
        scope: {
            sectionFilters: '=',
            sectionColumns: '='
        },
        controller: function ($scope, $route, $timeout, $location, filterLogic, auditFormSectionRepository) {
            // do stuff
    }
});

FilterHeader指令

<filter-header filters="sectionFilters" columns="sectionColumns"></filter-header>

FilterHeader模板

prideModule.directive('filterHeader', function($log) {
    return {
        restrict: 'E',
        templateUrl: 'templates/common/filterHeader.html',
        scope: {
            filters: '=',
            columns: '='
        },
        controller: function ($scope, filterItemsRepository) {
            $log.info("$scope.filters");
            $log.info($scope.filters);
            // This will log the filters as expected, however the $$hashKey property is missing from the items
    }
});

更新1

我将代码从指令中删除并进入一个新的控制器来模仿上面提到的工作场景。 <!-- at this point, {{ filters }} produces the list of filters --> <form class="form-horizontal" ng-repeat="filter in filters"> <!-- at this point, nothing renders --> <label class="col-sm-2 control-label">{{ filter.friendlyName }}</label> </form> 现在按预期运行,ng-repeater再次出现。因此,某些内容肯定与 route-&gt; controller-&gt; directive-&gt;指令 vs route-&gt; controller-&gt;指令之间的区别有关。

值得一提的是,除了上面的代码之外,还有过滤器上的手表以及其他用途。

更新2:罪犯未被发现

我已经钉了它。但它还没有意义。似乎应该责怪$$hashKey元素。更改为form可解决此问题。我认为这可能是一个有角色的错误,因为我很难理解为什么这种情况可以在一种情况下发挥作用而不是另一种情况。

1 个答案:

答案 0 :(得分:1)

到目前为止已经发现了两个修复程序,但它们比修复程序更糟糕,因为我无法理解原始问题的原因。如果有人能指出真正的问题,我仍然感兴趣,但在此之前,这是我所拥有的最好的:

解决方案1 ​​

经过大量的研究,调试,头脑刮擦,重写,我幸运地遇到了一个解决方案。我对它不满意,因为它没有意义(除非有人可以为我详细说明)。

问题似乎与form元素有关,并且在嵌套在角ng-repeat s中时使用directive属性... !!!这必须是一个错误,对吗?

解决方案就像改变这个一样简单:

<form class="form-horizontal" ng-repeat="filter in filters">
    <label class="col-sm-2 control-label">{{ filter.friendlyName }}</label>
</form>

到此:

<div class="form-horizontal" ng-repeat="filter in filters">
    <label class="col-sm-2 control-label">{{ filter.friendlyName }}</label>
</div>

解决方案2

$scope变量似乎也在这个问题中起作用。如果我为这个特定变量重命名每个指令的$scope变量名称(即过滤器),使其对每个指令都是唯一的,form ng-repeat就可以了。这使得它似乎在指令中存在某种冲突。孤立的范围,但为什么这只是form ng-repeat的一个问题困扰我。因此,它仍然没有向我解释这种行为的根本原因是什么。