AngularJS升级(从1.5到1.6、1.7)会导致指令作用域绑定未定义。

12

我有以下代码:

angular
  .module('myApp')
  .directive('layout', function () {
      return {
          restrict: 'E',
          template: '<div ng-include="layoutCtrl.pageLayout"></div>',
          controller: 'LayoutController',
          controllerAs: 'layoutCtrl',
          bindToController: true,
          scope: {
              pageLayout: '=',
              pageConfiguration: '=',
              isPreview: '='
          }
      };
  });

angular
  .module('myApp')
  .controller('LayoutController', LayoutController);

function LayoutController($scope, LayoutDTO, LayoutPreviewDTO) {
    var self = this;
    self.layoutDTO = LayoutDTO;
    self.layoutPreviewDTO = LayoutPreviewDTO;
    var test = $scope;

    if(self.isPreview)
        self.layoutModel = new self.layoutPreviewDTO(self.pageConfiguration);
    else
        self.layoutModel = new self.layoutDTO(self.pageConfiguration);
}


<div>
    <layout page-layout="ctrl.layoutTemplateUrl" page-configuration="ctrl.pageConfiguration" is-preview="false"></layout>
</div>
在Angular 1.5.3版本中,这个功能按预期工作,我的控制器变量带有值。现在,自从我升级到1.6.x版本后,self.pageConfiguration现在是未定义的。
除了Angular版本之外,没有任何改变。
如何在我的控制器中获取传递到指令中的值?

你有查看 Angular 更新日志吗?是否有任何重大更改可能导致这段代码“无法工作”?具体是什么问题导致了代码无法工作?你是否同时更新了其他 ng 原生模块到相同的 Angular 版本? - Alon Eitan
self.pageConfiguration现在是"undefined",而不是我从html中传递的值 <layout page-layout="ctrl.model.layoutTemplateUrl" page-configuration="ctrl.model.pageConfiguration" is-preview="false"></layout>。 - drabbitharv
很遗憾,这个问题太广泛了。你能否创建一个 fiddle 来重现这个问题?因为不知道你如何调用这个指令,所以很难进行调试。 - Alon Eitan
问题标签下有一个“编辑”链接 - 点击它并更新答案。 - Alon Eitan
2个回答

18
AngularJS团队建议将依赖于作用域绑定的控制器代码移动到$onInit函数中。
function LayoutController($scope, LayoutDTO, LayoutPreviewDTO) {
    var self = this;
    this.$onInit = function () {
        // bindings will always be available here
        // regardless of the value of `preAssignBindingsEnabled`.
        self.layoutDTO = LayoutDTO;
        self.layoutPreviewDTO = LayoutPreviewDTO;
        var test = $scope;

        if(self.isPreview)
            self.layoutModel = new self.layoutPreviewDTO(self.pageConfiguration);
        else
            self.layoutModel = new self.layoutDTO(self.pageConfiguration);
    };
}

$compile:

由于bcd0d4,控制器实例上的预分配绑定默认已禁用。仍然可以将其重新启用,这应该有助于迁移。预分配绑定已被弃用,并将在未来版本中删除,因此我们强烈建议尽快将您的应用程序迁移到不依赖它上面。

依赖于绑定存在的初始化逻辑应该放在控制器的$onInit()方法中,该方法保证始终在绑定分配之后调用。

-- AngularJS Developer Guide - 从v1.5迁移到v1.6 - $compile


更新

AngularJS V1.7 已经移除了 $compileProvider.preAssignBindingsEnabled 标志。

AngularJS 团队强烈建议您尽快迁移应用程序,不要依赖此标志。 AngularJS V1.6 将于2018年7月1日停止使用。

来自文档:

由于 38f8c9,指令绑定不再在构造函数中可用。
以前支持 $compileProvider.preAssignBindingsEnabled 标志。该标志控制绑定是否在控制器构造函数内可用,或仅在 $onInit 钩子中可用。现在不再在构造函数中提供绑定。
要迁移您的代码:
  • 如果您指定了 $compileProvider.preAssignBindingsEnabled(true),则需要先迁移您的代码,以便可以将标志翻转为 false。有关如何执行此操作的说明,请参见 "从 1.5 迁移到 1.6" 指南。然后删除 $compileProvider.preAssignBindingsEnabled(true) 语句。

— AngularJS 开发人员指南 - 迁移到 V1.7 - 编译

注意:

在2018年7月1日,对于AngularJS 1.6的支持将结束。更多信息请参见 AngularJS MISC - 版本支持状态


好的,我会记住这个,在未来的版本中注意,谢谢你指出这篇文章。 - drabbitharv
@drabbitharv 你应该将这个标记为正确答案。 - Paul N

1

1
如果您正在尝试遵循迁移路径,那么这是一个不好的想法,因为这只会将其切换回1.5。正如@georgeawg所提到的,您应该使用$onInit()来纠正绑定。 - Joey Gutierrez
1
$compileProvider.preAssignBindingsEnabled 标志已从 AngularJS V1.7 中移除。 - georgeawg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接