为什么 $onInit() 不在 angular material 对话框中触发?

Why doesn't $onInit() fire in an angular material dialog?

背景:
在我正在进行的一个项目中,我们为系统的 UI 部分采用了 Angular Material 设计框架。我们将其与 AngularJS 1.6.2 和 TypeScript 2.1.5 结合使用。

我们不断遇到的一条建议是使用 AngularJS 生命周期挂钩,以备不时 AngularJS 被弃用,取而代之的是 Angular 2. 特别是, 引入了生命周期挂钩以使其更容易升级,因为这些挂钩 - 其中 $onInit() 是成员 - 是纯粹基于组件的设置的一部分,这是 Angular 2 的主要功能。

问题:
我们发现,当您定义一个实现 angular.IController 的对话框控制器并定义了 $onInit() 内容时...这些内容不会被执行。

问题示例打字稿:

// Bootstrap Angular to our example.
class App {
    public constructor() {
        angular.module('app', ['ui.router', 'ngMaterial']);
    }
}

let app: App = new App();

// Set up routing for the example...
class RouteConfig {
    constructor(
        $stateProvider: angular.ui.IStateProvider,
        $urlRouterProvider: angular.ui.IUrlRouterProvider,
        $locationProvider: angular.ILocationProvider
    ){
        $stateProvider.state('Main', {
            url: '/Main',
            templateUrl: 'app/Main.html',
            controller: 'mainController'
        });

        $urlRouterProvider.otherwise('/Main');

        $locationProvider.html5Mode({
            enabled: true,
            requireBase: false
        });
    }
}

angular.module('app').config(['$stateProvider', '$urlRouterProvider', '$locationProvider', RouteConfig]);

// Controller for the page that will launch the modal...
class MainController implements angular.IController {
    public static $inject: string[] = ['$mdDialog'];
    public constructor(public $mdDialog: angular.IDialogService) {
    }

    public $onInit(): void {
        console.log('This works.');
    }

    public onButtonClick(): void {
        this.$mdDialog.show({
            controller: ModalController,
            controllerAs: '$ctrl',
            templateUrl: '/App/myModalTemplate.html', // Contents of modal not important.
            parent: angular.element(document.body),
            fullscreen: true
        })
            .then(() => console.log('Modal closed.'),
                  () => console.log('Modal cancelled.'));
    }
}

angular.module('app').controller('mainController', MainController);

// Controller for the actual modal that should be triggering $onInit.
class ModalController implements angular.IController {
    public static $inject: string[] = ['$mdDialog'];
    public constructor(public $mdDialog: angular.IDialogService) {
        alert('ModalController.ctor fired!');
    }

    public $onInit(): void {
        // PROBLEM!  This never actually executes.
        alert('$onInit fired on modal!');
    }

    public ok(): void {
        this.$mdDialog.hide();
    }
}

angular.module('app').controller('modalController', ModalController);

app/Main.html

<div ng-controller="mainController as $ctrl"
     md-content
     layout-padding>
    <h4>Modal Lifecycle Hook Problem Example</h4>
    <md-button class="md-raised md-primary"
               ng-click="$ctrl.onButtonClick()">
        Show Modal
    </md-button>
</div>

app/myModalTemplate.html:

<md-dialog>
    <md-toolbar class="md-theme-light">
        <h2>Modal</h2>
    </md-toolbar>
    <md-dialog-content class="md-padding">
        Stuff, y'all.
    </md-dialog-content>
    <md-dialog-actions>
        <md-button class="md-primary"
                   ng-click="$ctrl.ok()">
            OK
        </md>
    </md-dialog-actions>
</md-dialog>

如果您设置了所有这些东西,运行 项目,您将看到一个带有按钮的页面。当您单击该按钮时,您只会收到一个警报——构造函数已触发。我 期望 你会收到两个警报:构造函数触发消息,以及 $onInit 触发消息。

因此,这导致了我的...

问题: 为什么如果 Material 设计对话框控制器实现 IController,显然生命周期挂钩不会触发?

在您的代码中有 angular.module('app').controller('modalController', ModalController);。我在你的代码中没有看到 modalController 所以怀疑这个控制器实际上从未被触发过。

我从 AngularJS 开始,我最近在实习期间遇到了同样的问题。我认为问题是你的 ModalController 没有被称为组件(它被称为 $mdDialog)所以它没有任何生命周期。

要解决此问题,您必须显式调用 $onInit 方法。也许您可以在 ModalController 构造函数中执行此操作。