如何在 Angular 1.5 中将 Angular 组件与 ui.bootstrap.modal 一起使用?

Posted

技术标签:

【中文标题】如何在 Angular 1.5 中将 Angular 组件与 ui.bootstrap.modal 一起使用?【英文标题】:How to use angular component with ui.bootstrap.modal in angular 1.5? 【发布时间】:2016-07-23 22:03:40 【问题描述】:

我想在 ui.bootstrap.modal 中使用 Angular 组件。角度版本是 1.5。 我试着像下面这样使用。

组件

function MyComponentController($uibModalInstance)
  var ctrl = this;

  ctrl.doSomething = function() 
    //doSomething
  


app.component('myComponent', 
  contoller: MyComponentController,
  templateUrl: '/path/to/myComponent.html'

父控制器

function parentController($uibModal)
  var ctrl = this;

  ctrl.openModal = function()
    var modalInstance = $uibModal.open(
      template: '<my-component></my-component>'

  

当我执行 parentController.openModal() 时,虽然模式窗口已打开,但我收到了 $injector:unpr Unknown Provider 的错误。 有没有办法将角度组件与 ui.bootstrap.modal 一起使用? 如果您需要更多信息,请告诉我。 谢谢。

编辑 我有办法使用来自 Renato Machado 的 ui.bootstrap.modal 组件,谢谢 Renato。 但我觉得有点复杂,不方便。所以最后我认为最好在模态中使用组件。 模态以常规方式打开(只需在$uibModal.open() 中设置控制器和模板),并且模态包含您想要常用的逻辑的组件。 模态应该只有与模态相关的简单逻辑,比如关闭模态窗口。 另一个主要与业务/应用相关的逻辑应该在组件中。 它很容易通用化。

【问题讨论】:

你是否在你的应用中注入了对 ui.bootstrap 的依赖? 是的,我已经像下面这样注入了。 var app = angular.module('clientApp', ['ngAnimate', 'ngCookies', 'ngResource', 'ngRoute', 'ngSanitize', 'ngTouch', 'LocalStorageModule', 'ui.bootstrap' ]) 您的项目中是否包含所有文件? @Jyoti 是的,所有文件都包含在我的项目中。所以我可以打开模态窗口,但我得到了错误:( "component (Type: string, Example: myComponent) - 对要渲染的组件的字符串引用,该组件在 Angular 的编译器中注册。”可以在这里找到:angular-ui.github.io/bootstrap/#!#options-parameter :) 【参考方案1】:

您需要将父控制器传递给带有模态实例的模态组件。为此,您需要在父组件中附加模式的生成 HTML

父组件

$ctrl.openModal = function()
    $ctrl.modalInstance = $uibModal.open(
        template: '<your-modal></your-modal>',
        appendTo : $document.find('parentComponent')
    );

模态组件

.component('yourModal', 
        templateUrl: 'path/to/modal.html',
        replace: true,
        require: 
            parent : '^parentComponent'
        ,
        controller: ModalCtrl
    );

function ModalCtrl() 
    var $ctrl = this;

    $ctrl.$onInit = function()

        var instance = $ctrl.parent.modalInstance;

        $ctrl.items = ['item1', 'item2', 'item3'];

        $ctrl.selected = 
            item: $ctrl.items[0]
        ;

        $ctrl.ok = function () 
            instance.close($ctrl.selected);
        ;

        $ctrl.cancel = function () 
            instance.dismiss('cancel');
        ;

        instance.result.then(function (selectedItem) 
            $ctrl.selected = selectedItem;
        , function () 
            console.log('Modal dismissed at: ' + new Date());
        );
    ;



要小心,因为所需的控制器仅在 $onInit 之后可用。

【讨论】:

感谢您的回答。但它似乎不适用于我的环境。当我想从模板调用$ctrl.$onInit 中定义的函数时,如$ctrl.ok$ctrl.cancel,我应该怎么做?我试图通过以下方式调用它&lt;button ng-click="$ctrl.ok()"&gt;&lt;/button&gt; 哦,对不起,我弄错了。最后它似乎运作良好。非常感谢。【参考方案2】:

如果你想访问 $uibModal 的 $close()$dismiss() 函数,以及组件中的一些父数据和函数绑定,你可以这样传递它们:

打开模态逻辑

$uibModal.open(
    template: '<login close="$close()" dismiss="$dismiss()" ' +
        'email="$ctrl.cookieEmail" check-login="$ctrl.ajaxLogin(user, pass)"></login>',
    controller: function () 
        this.cookieEmail = $cookies.get('savedEmail');
        this.ajaxLogin = AjaxLoginService.login;
    ,
    controllerAs: '$ctrl'
);

模态登录组件


    templateUrl: 'view/login.html',
    bindings: 
        email: '<',
        checkLogin: '&',
        close: '&',
        dismiss: '&'
    ,
    controller: function () 
        var viewModel = this;

        viewModel.password = '';

        viewModel.submit = function () 
            viewModel.checkLogin(
                 user: viewModel.email, pass: viewModel.password 
            ).then(function (success) 
                viewModel.close();
            );
        
    

模态 HTML

<form ng-submit="$ctrl.submit()">
    <input type="text" ng-model="$ctrl.email" />
    <input type="password" ng-model="$ctrl.password" />
    <button type="button" ng-click="$ctrl.dismiss()">Cancel</button>
    <button type="submit">Login</button>
</form>

AngularJS 1.5 文档有点稀疏,但它们显示了 &amp; 绑定作为函数包装器的用法:https://docs.angularjs.org/guide/component

【讨论】:

【参考方案3】:

编辑:从 UI Bootstrap 2.1.0 开始,对 bootstrap modals 中的组件提供原生支持。看起来在 2.1.0 之后有几个快速版本来解决模态的一些问题,所以我一定要抓住最新的。

查看此 Plunk 了解使用 UI Bootstrap 2.1.0+ 的版本

http://plnkr.co/edit/jy8WHfJLnMMldMQRj1tf?p=preview

angular.module('app', ['ngAnimate', 'ui.bootstrap']);

angular.module('app')
  .component('myContent', 
     template: 'I am content! <button type="button" class="btn btn-default" ng-click="$ctrl.open()">Open Modal</button>',
     controller: function($uibModal) 
        $ctrl = this;
        $ctrl.dataForModal = 
        name: 'NameToEdit',
        value: 'ValueToEdit'
     

    $ctrl.open = function() 
      $uibModal.open(
         component: "myModal",
         resolve: 
           modalData: function() 
             return $ctrl.dataForModal;
           
         
       ).result.then(function(result) 
            console.info("I was closed, so do what I need to do myContent's  controller now.  Result was->");
      console.info(result);
       , function(reason) 
           console.info("I was dimissed, so do what I need to do myContent's controller now.  Reason was->" + reason);
       );
    ;
  
);

angular.module('app')
  .component('myModal', 
template: `<div class="modal-body"><div>$ctrl.greeting</div> 
<label>Name To Edit</label> <input ng-model="$ctrl.modalData.name"><br>
<label>Value To Edit</label> <input ng-model="$ctrl.modalData.value"><br>
<button class="btn btn-warning" type="button" ng-click="$ctrl.handleClose()">Close Modal</button>
<button class="btn btn-warning" type="button" ng-click="$ctrl.handleDismiss()">Dimiss Modal</button>
</div>`,
  bindings: 
    modalInstance: "<",
    resolve: "<"
  ,
  controller: [function() 
    var $ctrl = this;
    $ctrl.$onInit = function() 
      $ctrl.modalData = $ctrl.resolve.modalData;
    
    $ctrl.handleClose = function() 
      console.info("in handle close");
      $ctrl.modalInstance.close($ctrl.modalData);
    ;
    $ctrl.handleDismiss = function() 
      console.info("in handle dismiss");
      $ctrl.modalInstance.dismiss("cancel");
    ;
  ]
);

原答案如下:

前几天我也想弄清楚这一点。我把我在这篇文章中找到的信息和这个链接一起尝试想出另一种方法来实现这一点。这些是我发现对我有帮助的一些参考链接:

https://github.com/angular-ui/bootstrap/issues/5683

http://www.codelord.net/(这有助于理解将参数传递给组件中的回调)

这里还有一个 Plunk:http://plnkr.co/edit/PjQdBUq0akXP2fn5sYZs?p=preview

我试图演示一个常见的现实世界场景,即使用模式编辑一些数据。

angular.module('app', ['ngAnimate', 'ui.bootstrap']);

angular.module('app')
.component('myContent', 
    template: 'I am content! <button type="button" class="btn btn-default" ng-click="$ctrl.open()">Open Modal</button>',
    controller: function($uibModal) 
        $ctrl = this;
        $ctrl.dataForModal = 
            name: 'NameToEdit',
            value: 'ValueToEdit'
        
        $ctrl.open = function() 
            $uibModal.open(
                template: '<my-modal greeting="$ctrl.greeting" modal-data="$ctrl.modalData" $close="$close(result)" $dismiss="$dismiss(reason)"></my-modal>',
                controller: ['modalData', function(modalData) 
                    var $ctrl = this;
                    $ctrl.greeting = 'I am a modal!'
                    $ctrl.modalData = modalData;
                ],
                controllerAs: '$ctrl',
                resolve: 
                    modalData: $ctrl.dataForModal
                
            ).result.then(function(result) 
                console.info("I was closed, so do what I need to do myContent's controller now and result was->");
                console.info(result);
            , function(reason) 
                console.info("I was dimissed, so do what I need to do myContent's controller now and reason was->" + reason);
            );
        ;
    
);

angular.module('app')
.component('myModal', 
    template: `<div class="modal-body"><div>$ctrl.greeting</div> 
<label>Name To Edit</label> <input ng-model="$ctrl.modalData.name"><br>
<label>Value To Edit</label> <input ng-model="$ctrl.modalData.value"><br>
<button class="btn btn-warning" type="button" ng-click="$ctrl.handleClose()">Close Modal</button>
<button class="btn btn-warning" type="button" ng-click="$ctrl.handleDismiss()">Dimiss Modal</button>
</div>`,
    bindings: 
        $close: '&',
        $dismiss: '&',
        greeting: '<',
        modalData: '<'
    ,
    controller: [function() 
        var $ctrl = this;
        $ctrl.handleClose = function() 
            console.info("in handle close");
            $ctrl.$close(
                result: $ctrl.modalData
            );
        ;
        $ctrl.handleDismiss = function() 
            console.info("in handle dismiss");
            $ctrl.$dismiss(
                reason: 'cancel'
            );
        ;
    ],
);

【讨论】:

我找到的最好的解决方案。 Plunk 使重新调整用途变得容易。谢谢。 谢谢,我错过了承诺处理程序 这是一个很好的答案。我使用的是带有模板+控制器的旧版本的 ui-bootstrap,并且不知道对组件的支持。 Plunk 非常乐于助人,而且效果很好。谢谢。 这是我找到的最佳答案,就像一个魅力!我只有一个问题,为什么你使用 '.result.then(func..' 作为承诺处理程序而不是 '.result(func..' 或 '.then(func..'?跨度> 认为您更新的代码有错误 - 应该是 $ctrl.$onInit 而不是 $ctrl.$init【参考方案4】:

没有必要通过传递父控制器使其变得更复杂,您可以从显示模式的 .component 中访问它。

组件

/**
 * @ngdoc component
 * @name fsad.component:video
 *
 * @description <fsad-video> component, in development...
 *
 */


(function () 
  'use strict';

  angular.module('fsad').component('fsadVideo', 
    bindings: ,
    templateUrl: function(appConstant)return appConstant.paths.modules.fsad + 'leefloon/fsad-video.html',
    controller: controller
  );

  controller.$inject = ['$scope'];
  function controller($scope)

    var $ctrl = this;

    setDataModel();

    /****************************************************************/

    $ctrl.ui.close = close;

    /****************************************************************/

    function setDataModel()

      $ctrl.ui = ;

    
    function close()
      $scope.$parent.$close();
    

  

());

打开模态

  var modalInstance = $uibModal.open(
    backdrop: 'static',
    keyboard: true,
    backdropClick: false,
    template: '<fsad-video></fsad-video>',
    windowClass: 'edit-contactenblad',
  );

由于您声明模板是一个组件,$scope.$parent 将始终指向模态实例。允许您访问 $close() 函数。

传递和接收数据

如果你需要向组件传递数据,或者从组件接收数据,你可以这样做。

  var modalInstance = $uibModal.open(
    backdrop: 'static',
    keyboard: true,
    backdropClick: false,
    template: '<fsad-video method="$ctrl.method" on-viewed="$ctrl.userHasViewedVideo(time)"></fsad-ideo>',
    controller: function()
      this.method = method;
      this.userHasViewedVideo = function(time)
    ,
    controllerAs: '$ctrl',
    windowClass: 'edit-medewerker',
  );

顺便说一句,我正在使用这个structure style guide 来创建组件。

【讨论】:

以上是关于如何在 Angular 1.5 中将 Angular 组件与 ui.bootstrap.modal 一起使用?的主要内容,如果未能解决你的问题,请参考以下文章

前端小白之每天学习记录----angula2--

如何在 Angular 1.5 组件中监听范围事件?

如何在 Angular 1.5 中注入组件路由器?

如何从 Angular 1.5 组件中获取表单验证

angular 1.5 如何创建年份选择器下拉菜单

如何在 Angular 1.5 中使用 HTML 选择调用父组件