使用 angular-ui-router 和 bootstrap $modal 创建一个多步骤向导

Posted

技术标签:

【中文标题】使用 angular-ui-router 和 bootstrap $modal 创建一个多步骤向导【英文标题】:use angular-ui-router with bootstrap $modal to create a multi-step wizard 【发布时间】:2014-02-17 12:35:14 【问题描述】:

FAQ for ui-router 有一个关于与 bootstrap $modals 集成的部分,但它没有提到任何关于抽象视图的内容。我在一个抽象视图下有 3 个视图,所以类似于以下内容。

 $stateProvider
   .state('setup', 
     url: '/setup',
     templateUrl: 'initialSetup.html',
     controller: 'InitialSetupCtrl',
     'abstract': true
   )  

   // markup for the static view is
   <div class="wizard">
     <div ui-view></div>
   </div> 

   .state('setup.stepOne', 
      url: '/stepOne',
      controller: 'SetupStepOneCtrl',
      onEnter: function($stateParams, $state, $modal) 
        $modal.open
          backdrop: 'static',
          templateUrl: 'setup.stepOne.html',
          controller: 'SetupStepOneCtrl'
        )
         
   )  

   .state('setup.stepTwo', 
     url: '/stepTwo',
     controller: 'SetupStepTwoCtrl',
     onEnter: function($stateParams, $state, $modal) 
       $modal.open(
         backdrop: 'static',
         templateUrl: 'setup.stepTwo.html',
         controller: 'SetupStepTwoCtrl'
       )
        
    )  

    .state('setup.stepThree', 
      url: '/stepThree',
      templateUrl: 'setup.stepThree.html',
      controller: 'SetupStepThreeCtrl'
      ...
    ); 
]);

我还尝试仅将 onEnter 块添加到抽象状态,并从 3 个子状态中的每一个中删除 onEnter。在我看来,这实际上是正确的方法。抽象状态初始化并打开 $modal 并且后续状态应该插入到 中,但是当我尝试这样做时,ui-view 容器是空的。

我可以想到一些其他的破解方法来解决这个问题,但我想我想看看是否有处理这个问题的规范方法。

【问题讨论】:

嗨,我也在尝试做同样的事情,你解决了吗 这里也一样,我也有同样的问题。有什么解决办法吗? 不,我从来没有让它工作,对不起。 我正在做这件事。到目前为止,我有来自常见问题解答的示例。 使用ngIncludestateChangeStart 让它工作。基本上我在状态变化时动态注入模板 【参考方案1】:

要创建多步向导,可以使用这个模块(我是作者):https://github.com/troch/angular-multi-step-form。

它允许您创建像视图这样的步骤,并且您可以启用导航(后退/前进按钮,带有 URL 搜索参数的 url)。示例可用here。

【讨论】:

【参考方案2】:

另一种方法是在$modal 控制器内使用ng-switchng-include 组合来动态加载向导步骤模板,也就是说,如果您不介意为所有向导步骤共享同一个控制器:

<div ng-switch="currentStep.number">
  <div ng-switch-when="1">
    <ng-include src="'wizardModalStep1.html'"></ng-include>
  </div>
  <div ng-switch-when="2">
    <ng-include src="'wizardModalStep2.html'"></ng-include>
  </div>
  <div ng-switch-when="3">
    <ng-include src="'wizardModalStep3.html'"></ng-include>
  </div>
</div>

这是带有工作示例的 Plunker:http://plnkr.co/edit/Og2U2fZSc3VECtPdnhS1?p=preview

希望对某人有所帮助!

【讨论】:

【参考方案3】:

如果您想在模态对话框中显示一个向导并为向导的每个步骤设置一个单独的状态,您需要记住模态对话框完全在您的视图层次结构之外呈现。因此,您不能期望ui-router 的视图呈现机制和对话框内容之间有任何交互。

一个健壮的解决方案是将向导内容操作逻辑放到父状态范围

$scope.wizard = 
    scope: $scope.$new(),
    show: function (template) 
        // open the $modal if not open yet
        // purge scope using angular.copy()
        // return $scope.wizard.scope
    ,
    // private
    open: function () 
        $modal.open(
            scope: $scope.wizard.scope,
            // ...
        );
    
;

然后手动显示每个子状态的相应内容,并根据需要操纵向导的范围

$scope.wizard.show('someTemplate');
$scope.wizard.scope.user = ...;

当我们在项目中遇到这个问题时,我们经过一番讨论后决定,我们实际上不需要单独的ui-router 状态用于向导步骤。这允许我们在对话框模板中创建一个wizard 指令,用于从范围读取向导配置(使用类似于ui-router 状态定义的格式),提供推进向导的方法,并在对话框中呈现适当的视图/控制器.

【讨论】:

【参考方案4】:

我遇到了同样的事情。对我有用的是清空第一个子状态的 url 属性。因此,对于第一个子状态,您的代码应如下所示:

    .state('setup.stepOne', 
      url: '',
      controller: 'SetupStepOneCtrl',
      onEnter: function($stateParams, $state, $modal) 
        $modal.open
          backdrop: 'static',
          templateUrl: 'setup.stepOne.html',
          controller: 'SetupStepOneCtrl'
        )
         
   )  

另外,如果您没有使用 url 属性来调用其他 3 个子状态,并且仅使用状态名称来调用它们,则不一定需要为它们提及 url 属性。

【讨论】:

【参考方案5】:

我使用以下方法来开发向导。这可能对你有帮助。

我使用了像下面带有 parent 属性的示例的状态。

 var home = 
            name: 'home',
            url: '/home',
            controller: 'MainController',
            templateUrl: '/html/main.html'
        ,
        sampleWizard = 
            name: 'sampleWizard',
            url: '/sampleWizard',
            controller: 'sampleWizardController',
            templateUrl: '/html/sd/sample/sampleWizard.html'
        ,
         sampleSectionOne = 
             name: 'sampleSectionOne',
             url: '/sampleSectionOne',
             parent: sampleWizard,
            controller: 'sampleSectionOneController',
            templateUrl: '/html/sd/sample/sampleSectionOne.html'
        ,
        sampleSectionTwo = 
            name: 'sampleSectionTwo',
            url: '/sampleSectionTwo',
            parent: sampleWizard,
            controller: 'sampleSectionTwoController',
            templateUrl: '/html/sd/sample/sampleSectionTwo.html'
        ;

        $stateProvider.state(home);
        $stateProvider.state(sampleWizard);
        $stateProvider.state(sampleSectionOne);
        $stateProvider.state(sampleSectionTwo);

【讨论】:

【参考方案6】:

我已经处理过类似的情况,我必须创建一个向导(它允许您完成步骤并最终点击摘要并保存)。 为此,我使用一个控制器创建了不同的视图。 由于控制器范围在每次重新路由后都会消失,因此我必须将控制器的范围(基本上是与向导关联的模型对象)保存在向导中每个路由的服务对象中(通过 location.path() 捕获)并加载它在控制器加载时从服务对象返回对象。如下所示:-

// Saving data on routing
 $scope.nextPage = function () 
        service.ModelForWizard = $scope.ModelForWizard;
        switch ($location.path()) 
        case RouteOfPage1:
            //Do some stuff
            break;
        case RouteOfPage2:
           //Do some stuff
            break;

        default:

服务或工厂在用户会话的整个生命周期中都保持不变,是保存用户数据的理想选择。 另一件有帮助的事情是在路线中使用“解决”。 它确保在未加载所需数据(通常是查找数据)之前不会呈现下一页。解析代码是这样的:

.when('/RouteForWizardPage1', 
                templateUrl: '/templates/ViewPage1Wizard.html',
                caseInsensitiveMatch: true,
                controller: 'wizardController',
                resolve: 
                   wizardLookupDataPage1: function (Service) 
                        return service.getwizardModelLookupDataPage1().$promise;
                    
                ,
            )

【讨论】:

【参考方案7】:

我不确定您是否要在每次进入下一步时触发模态。

我认为你所要做的就是创建一个模态视图 () 然后每个步骤都有一个模态的 templateUrl 分配给它。

每个模板应如下所示:


<div class="modal fade in" id="whatever" style="display:block">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
                <h4 class="modal-title">Modal title</h4>
            </div>
            <div class="modal-body">
                <p>One fine body&hellip;</p>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                <a ui-sref="next_page_route_id" type="button" class="btn btn-primary">Next</a>
            </div>
        </div><!-- /.modal-content -->
    </div><!-- /.modal-dialog -->
</div><!-- /.modal -->

<div class="modal-backdrop fade in"></div>

在最后一个屏幕上,您可以在提交中添加 data-dismiss="modal" 即可完成

【讨论】:

以上是关于使用 angular-ui-router 和 bootstrap $modal 创建一个多步骤向导的主要内容,如果未能解决你的问题,请参考以下文章

angular-ui-router 使用打字稿嵌套命名视图

带有 Html5Mode 的 Angular-UI-Router 刷新页面问题

Angular-ui-router 详解

控制器内部的 angular-ui-router 函数不是函数

Angular-ui-router 打字稿定义

(Angular-ui-router) 在解析过程中显示加载动画