为什么$ onInit()不会在角度材质对话框中触发?

时间:2017-03-08 16:23:21

标签: angularjs typescript lifecycle angularjs-material

背景
在我正在进行的项目中,我们已经为系统的UI部分采用了Angular Material Design框架。我们将此与AngularJS 1.6.2和TypeScript 2.1.5结合使用。

我们一直在遇到的一条建议就是使用AngularJS生命周期钩子,以便在AngularJS被弃用以支持Angular 2时做好准备。具体来说,引入生命周期钩子以使其更容易升级,因为这些钩子 - 其中$onInit()是成员 - 是纯粹基于组件的设置的一部分,这是Angular 2的主要特性。

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

问题示例TypeScript:

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

应用/ 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>

应用/ 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 Design Dialog控制器实现IController,显然生命周期挂钩不会触发?

2 个答案:

答案 0 :(得分:1)

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

要解决此问题,您必须明确调用$onInit方法。也许你可以在你的ModalController构造函数中做到这一点。

答案 1 :(得分:-2)

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