【问题标题】:Why is binding lost when nesting directive in directive?为什么在指令中嵌套指令时绑定丢失?
【发布时间】:2016-02-23 12:16:18
【问题描述】:

问题

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

该指令在我的应用程序的许多领域中使用,没有问题。它呈现从父模板传递到其范围的输入列表,如下所示:

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

工作场景

我在整个申请过程中使用了以下场景,迄今为止没有遇到任何问题。

  • $routeProvider 使用控制器的 WebAPI 调用解析过滤器列表
  • 控制器将列表分配给自己的范围,如下所示:$scope.filters = filters
  • 模板使用 filter-header 元素并将过滤器从它的范围传递到指令,如下所示:&lt;filter-header filters="filters"&gt;&lt;/filter-header&gt;
  • filter-header 指令然后使用 ng-repeat 呈现过滤器而不会出现问题。 $$hashKey 存在于过滤器集合的每个项目中,表明绑定的存在。

失败场景

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

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

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


古怪

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


深入研究...

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

为了确定这不是我的列表引起的问题,我使用了一个已经使用上述工作场景的列表,并且ng-repeat 不会在此处呈现。

为了确定这不是我的指令代码导致的问题,我将它转换为控制器并直接路由到它(跳过嵌套指令),就像上面提到的工作场景一样,ng-repeat 现在可以工作了。

使用$log 检查列表,我注意到一个不同之处。在工作场景中,所有列表都包含列表中每个项目的$$hashKey 属性。在失败的情况下,列表中的所有项目都缺少$$hashKey。这似乎表明绑定由于某种原因正在丢失。

有人可以告诉我我的方式中的错误吗?我在使用中可以看到的唯一真正区别是,我先将对象传递给中间人指令,然后再将其传递给使用它的指令。奇怪的是,在同一个指令中,另一个列表以非常相似的方式使用,它在 ng-repeat 内毫无问题地呈现,并且它的所有项目都附加了 $$hashKey 属性。


代码

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

路由提供者

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

EditAuditForm 模板

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

AuditAdminSections 指令

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

AuditFormSections 模板

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

FilterHeader 模板

<!-- 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>

更新 1

我将代码从指令中提取出来,放到一个新的控制器中来模拟上面提到的工作场景。 ng-repeater 现在按预期运行,$$hashKey 再次出现。所以某些东西肯定与 route->controller->directive->directiveroute->controller->directive 之间的区别有关。

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

更新 2:发现罪犯

我已经搞定了。但这还没有意义。似乎form 元素是罪魁祸首。更改为 div 可解决此问题。我认为这可能是一个有角度的错误,因为我正在努力了解为什么这可以在一种情况下而不是另一种情况下工作。

【问题讨论】:

  • 你能提供更多代码 - 相关的 html/js 片段吗?
  • $$hashkeyng-repeat 添加到您的收藏中。您看不到那些hashkey 的事实意味着在您的控制器和ng-repeat 之间的某个地方绑定已损坏。没有错别字?在名为 filters? 的子/父范围内也没有其他变量
  • 请发布您的代码
  • 请记住,ng-repeat 创建了它自己的范围,也许这是你的问题
  • 我尝试将代码从指令中提取并放入控制器中(这样它就可以像工作场景一样工作。这种方式没有问题,现在 $hashKey 存在。

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


【解决方案1】:

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

解决方案 1

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

问题似乎在于form 元素并在其上使用ng-repeat 属性,同时嵌套在角度directives 中......!!!这一定是个bug吧?

解决方法就这么简单:

<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 的问题让我感到困惑。因此,它仍然没有向我解释这种行为的根本原因是什么。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-09-24
    • 2013-08-26
    • 2015-10-22
    • 1970-01-01
    • 1970-01-01
    • 2018-05-21
    • 2012-12-14
    • 2013-06-15
    相关资源
    最近更新 更多