使用给定的 parent 绑定控制器

Bind a controller with a given parent

使用 Angular Bootstrap 和 $modal 服务,我使用以下模板创建了一个弹出窗口:

<div class="dialog modal-header" ng-show="header.length > 0">
    <h3 compile="header"></h3>
</div>
<div class="dialog modal-body">
    <div compile="bodyTemplate"></div>
</div>
<div class="dialog modal-footer">
    <button ng-repeat="button in buttons"
            ng-show="$parent.$eval(button.showExpression)"
            ng-class="button.class"
            ng-click="onButtonClick(button)">
        <div compile="button.template"/>
    </button>
</div>

我构建了一个弹出服务来帮助设置范围的默认值,以及从 templateUrl 加载 bodyTemplate。

// snippit of my popup service
function show(modalOptions, scope) {

    // ....
    // load template from modalOptions.bodyTemplateUrl
    // ....

    var extendedModalOptions = {};
    angular.extend(extendedModalOptions, defaultModelOptions, modalOptions);

    extendedModalOptions.controller = function ($scope, $modalInstance) {
        angular.extend($scope, scope);

        // .... 
        // add to $scope additional properties from the extendedModalOptions 
        // such as the buttons array and loaded bodyTemplate
        // ....
    }
    $modal.open(extendedModalOptions);
}

我想要的是注入一个用于bodyTemplate的控制器,像这样:

<div class="dialog modal-header" ng-show="header.length > 0">
    <h3 compile="header"></h3>
</div>

<!-- Note the addition of ng-controller here -->
<div class="dialog modal-body" ng-controller="bodyController">
    <div compile="bodyTemplate"></div>
</div>

<div class="dialog modal-footer">
    <button ng-repeat="button in buttons"
            ng-show="$parent.$eval(button.showExpression)"
            ng-class="button.class"
            ng-click="onButtonClick(button)">
        <div compile="button.template"/>
    </button>
</div>

这可以工作,但是,bodyController 作用域的 $parent 现在是给 $modal 控制器的作用域。我想使用不同的 parent.

我希望能够像这样使用我的弹出服务:

// from inside CustomerController
popup.show({
    header: 'Test Popup',
    parentScope: $scope, // the current scope of CustomerController
    bodyTemplateUrl: 'testPopupTemplate.html',
    bodyController: 'TestPopupController as testPopupVM'
});

这是我有点迷路的地方。我认为我的弹出服务可以像这样创建控制器:

$scope.bodyController = $controller(extendedModalOptions.bodyController, {
    $scope: extendedModalOptions.parentScope
});

我不是 100% 确定,但我认为这让我的控制器具有正确的 parent。然而,问题是返回值是新作用域object,而不是构造函数。

根据 ng-controller 上的 angular 文档,它只能绑定到构造函数。

如何在使用提供的 parent 范围时将主体控制器添加到弹出模板?

您正在尝试创建自己的 $scope 层次结构,而 Angular 提供的层次结构就可以了。

默认情况下,使用 $modal 服务打开的模式从 $rootScope 获取新的子作用域。您可以通过显式设置基本模态范围来更改此设置,即

$modal({
    scope: yourBaseScope
    // other modal options
})

Modal 将在创建时调用 yourBaseScope.$new() 并使用它。因此,它将可以访问您在 yourBaseScope.

中定义的所有变量和函数

阅读更多关于模态范围的信息in docs

fracz 的答案是更好的选择,但我想提供一个替代 hack。

由于ng-controller只能绑定一个controller function,所以我在popup service里面建了一个:

$scope.bodyCtrl = function($scope) {
   // HACK: replace the parent with the one from extendedModalOptions
   $scope.$parent = extendedModalOptions.parentScope;

   return $controller(extendedModalOptions.bodyController, {
       $scope: $scope
   });
};
// annotate the controller function so minification does't break injection
$scope.bodyCtrl['$inject'] = ['$scope'];

手动替换作用域上的 $parent 有代码味。我没有意识到你可以传递 $rootScope 替代 $modal.