如何使用$ routeProvider打开AngularJS 1.x中的ui-modal中的现有控制器/视图

时间:2016-10-21 13:38:54

标签: angularjs angular-ui-bootstrap ngroute

我知道这可以通过ui-router实现,而且在角度2中这不再是一个问题。但对于我们的实际项目,我们暂时陷入了角度1.x和$ routeProvider的困境。

所以我想要的是打开一个现有的组件(例如一个登录表单),它已经生活了#34;在它自己的页面中,或者在模态对话框($ uibModal)上,无需复制或修改它的控制器或模板。

最简单的示例是登录表单,拥有自己的路由,例如可以通过myapp/#/login访问,现在我也希望将其显示在当前"页面的顶部"作为模态,无需修改控制器/模板等。当模态消失后,我希望下面的页面处于与我离开时相同的状态。

此解决方案适用于任何视图,而不仅仅是登录表单(作为示例)。所以我正在寻找通用的解决方案。

有什么想法吗?

1 个答案:

答案 0 :(得分:0)

经过一番尝试,我终于得到了我想要的东西:

首先我创建了一个服务,它负责打开泛型模态。我叫它genericModalSvc 值得一提的是,我正在使用名为namedRouteSvc的服务来获取 每个名字的路线和其他很酷的东西。路由名称定义为自定义 路线上的参数如下:

$routeProvider
    .when('/something', {
        name: 'something', // this is a custom parameter to retrieve the route
        templateUrl: 'something.html',
        controller: 'SomethingCtrl',
        controllerAs: 'ctrl'
    })

以上对于genericModalSvc来说不是必需的,但它可以解决问题 更容易理解下面的代码:

angular
    .module('my_app.common_stuff')
    .service('GenericModalSvc', GenericModalSvc);

GenericModalSvc.$inject = ['$uibModal', '$rootScope', 'namedRouteSvc'];
function GenericModalSvc($uibModal, $rootScope, namedRouteSvc) {
    this.$uibModal = $uibModal;
    this.$rootScope = $rootScope;
    this.namedRouteSvc = namedRouteSvc;

    this.modalInstance = null;

    // Broadcasts for close signal from modal's close button
    this.$rootScope.$on('GenericModalCloseClicked', this.close.bind(this));
}


GenericModalSvc.prototype.close = function() {
    this.modalInstance.close();
    // Emit a signal here, for other listeners to know the modal has been
    // closed.
    this.$rootScope.$emit('GENERIC_MODAL_CLOSED');
};

GenericModalSvc.prototype.open = function(params) {
    // The params argument here, has route information and parameters I
    // want to transfer to the model
    var route_name = params.route_name, // A string defined in each route
        args = params.args,       // The route parameters
        query = params.query,     // The route query arguments
        options = params.options; // Other options

    this.$rootScope.$emit('GENERIC_MODAL_OPENED');
    var route = this.namedRouteService.getRoute(route_name, args, query);
    route = route.hasOwnProperty('route') ? route.route : null;

    if (!route) {
        throw new Error('Could not find a route for the given parameters');
    }

    var modal_title = params.options.modal_title;

    // The following is the fun part. Now we can use the route to get the
    // controller and controllerAs attributes to define our modal here.
    this.modalInstance = this.$uibModal.open({
        // This template is the modal wrapper for our 'real' template.
        templateUrl: 'partials/generic-modal.html',
        controller: route.controller,
        controllerAs: route.controllerAs,
        backdrop: 'static',
        size: 'lg',
        resolve: {
            show_modal_close: function() {
                return Boolean(options && options.showCloseButton);
            },
            modal_title: function() {
                return modal_title;
            },
            template_to_render: function() {
                // We need to pass this information to our generic-modal.html
                // template to include it there.
                return route.templateUrl;
            },
            dummy: function($routeParams) {
                // This is a rather kind of q&d way of passing the route 
                // parameters and query arguments. On the controller, we
                // must look inside $routeParams for 'modalParameters' first 
                // (because we don't know there if we're inside a modal or not)
                // and if 'modalParameters' doesn't exist, then we retrieve the 
                // normal-ones inside $routeParams. I know, it's not perfect
                // but didn't come up with a better idea.
                $routeParams.modalParameters = {
                    routeParams: args,
                    queryParams: query
                };
            }
        }
    });
};

然后,generic-modal.html模板非常简单:

<p id="generic-modal-header">
    <button type="button" class="close" data-dismiss="modal" aria-label="Close"
        ng-click="$emit('GenericModalCloseClicked')">
        <span aria-hidden="true">X</span></button></p>

<div id="generic-modal-container">
    <div ng-include="$resolve.template_to_render"></div>
</div>

最后这是一个如何使用它的例子:

angular
    .module('my_app.foo')
    .controller('FooCtrl', FooCtrl);
FooCtrl.$inject = ['...','genericModalSvc'];
function FooCtrl(..., genericModalSvc) {
    this.genericModalSvc = genericModalSvc;
}

FooCtrl.prototype.openBarDetailsOnModal = function() {
    var params = {
        route_name: 'bar-detail',
        args: {'id': this.some_id_for_bar},
        query: {},
        options: {}
    };
    this.genericModalSvc.open(params);
};

就是这样!!!