调查表的“下一步”按钮的逻辑

Logic for the Next button for the questionnaire?

本文关键字:下一步 按钮 调查表      更新时间:2023-09-26

我是AngularJS的初学者,面临一些问题。我正在尝试制作一份问卷,每页上有 1 个问题。在每个"下一步"按钮上,数据都保存在数据库中。我正在尝试制作下一个按钮逻辑,但不知道如何制作一个通用的 NEXT 按钮逻辑,该逻辑使用 ng-show 启用下一个字段,禁用当前字段,最后将字段的当前值存储在数据库中。有人可以帮助为下一步按钮制作一个逻辑,该逻辑将在下一页上启用下一个div显示并将数据存储在数据库中?

网页代码:

<div class="container">
 <div class="row-fluid">
    <section class="col-md-12 well">
        <h1><i class="fa fa-key"></i>User Creation</h1>
        <hr />
        <form class="form-horizontal">
            <div class="alert alert-info" role="alert">
                <strong><i class="fa fa-info-circle"></i> Basic Information </strong>
            </div>
            <div class="form-group" ng-show="firstNameDiv">
                <label class="col-sm-2 control-label" for="firstName">First Name</label>
                <div class="col-sm-10">
                    <input type="text" class="form-control" id="firstName" placeholder="First Name" ng-model="user.firstName" required />
                </div>
            </div>
             <div class="form-group" ng-show="middleNameDiv">
                <label class="col-sm-2 control-label" for="middleName">Middle Name</label>
                <div class="col-sm-10">
                    <input type="text" class="form-control" id="middleName" placeholder="Middle Name" ng-model="user.middleName" />
                </div>
            </div>
             <div class="form-group" ng-show="lastNameDiv">
                <label class="col-sm-2 control-label" for="lastName">Last Name</label>
                <div class="col-sm-10">
                    <input type="text" class="form-control" id="lastName" placeholder="Last Name" ng-model="user.lastName" />
                </div>
            </div>
            <div class="form-group" ng-show="genderDiv">
                <label class="col-sm-2 control-label" for="gender">Gender</label>
                <div class="col-sm-10">
                    <div class="radio">
                        <label><input type="radio" name="male" ng-model="user.gender">Male</label>
                    </div>
                    <div class="radio">
                        <label><input type="radio" name="female" ng-model="user.gender" disabled>Female</label>
                    </div>
                </div>
            </div>
            <div class="form-group" ng-show="ageDiv">
                <label class="col-sm-2 control-label" for="age">Age</label>
                <div class="col-sm-10">
                    <input type="text" class="form-control" id="age" placeholder="Age" ng-model="user.age" />
                </div>
            </div>
            <div class="form-group">
                <div class="col-sm-offset-2 col-sm-10">
                    <a href="#" class="btn btn-default"><i class="fa fa-arrow-circle-left"></i> Back</a>
                    <a href="#" class="btn btn-default"><i class="fa fa-arrow-circle-left" ng-click="next()"></i> Next</a>
                </div>
            </div>
        </form>
    </section>
</div>

Javascript:UserController.js

(function () {
'use strict';
angular.module('myApp').controller('UserCtrl', function ($scope, $rootScope,   $routeParams, $sanitize, $location, UserSrv) {
    // loading variable to show the spinning loading icon
    $scope.loading = false;
    $scope.init = function() {
        $scope.firstNameDiv = true;
        $scope.middleNameDiv = false;
        $scope.lastNameDiv = false;
        $scope.genderDiv = false;
        $scope.ageDiv = false;
    };
    // runs once per controller instantiation
    $scope.init();
    $scope.next = function() {
        $scope.firstNameDiv = false;
        // Call User service with firstNameDiv value.
        UserSrv.saveData();
        $scope.middleNameDiv = true;
        // Logic to enable next field and save the current field value 
        // ???
    }
});
}());

您可以创建一个多步骤表单(也称为向导(。为此,为什么不按照这篇文章中的建议使用Angular ui-router:

https://scotch.io/tutorials/angularjs-multi-step-form-using-ui-router

这是一个指导创建向导的教程,并有一个工作示例(Plunker(。

还有其他 Angular 模块旨在做同样的事情:

  • https://github.com/troch/angular-multi-step-form(此处为演示和文档(
  • https://github.com/mgonto/angular-wizard(此处演示(

总之,另一个带有工作演示的教程

  • http://code.realcrowd.com/the-wonderful-wizard-of-angularjs/

但是,如果您">谷歌"搜索"多步形式角度",您可以找到更多示例。

同样在StackOverflow上,您可以找到有关如何创建多步骤表单的建议(例如,请参阅AngularJS多步骤表单验证(。

您可以将 showDiv 布尔值保存在数组中,并将相应的索引保存在内存中。所以像这样:

$scope.currentState = 0;
//ordered representation of possible states
$scope.stateArray = [true, false, false, false, false];
$scope.next = function(){
  //on to the next showDiv
  currentState++;
  stateArray.forEach(function(index, state){
    //hide everything else.
    if(index != currentState){
      state = false;
    }
    else{
      state = true;
    }
  }
}

然后,在您的 html 中,执行ng-show="stateArray[currentState]"

如果你选择通过递减 currentState 来代替,你会无意中从中获得一个"上一个"函数。

我将创建三个可用于构建多部分表单的自定义指令:

  1. myMultiPartForm指令将包装表单并跟踪哪个部分可见
  2. myFormPart指令将多次用作每个表单部分的包装器
  3. myFormPartSubmit将用于每个表单部分中的提交按钮,以前进到下一部分

下面是一个工作示例:JSFiddle

索引.html

在此文件中,我使用 MyViewController 作为视图,它将公开一个 part 变量,用于跟踪当前正在显示的表单部分,以及每个表单部分在提交时可以调用的save方法。

<div ng-app="myApp" ng-controller="MyViewController as view">
  <my-multi-part-form part="{{view.part}}">
    <my-form-part on-submit="view.save(data)">
      <label>
        Name:
        <input type="text" ng-model="formPart.data.name">
      </label>
      <button my-form-part-submit>
        Next
      </button>
    </my-form-part>
    <my-form-part on-submit="view.save(data)">
      <label>
        Age:
        <input type="number" ng-model="formPart.data.age">
      </label>
      <button my-form-part-submit>
        Next
      </button>
    </my-form-part>
    <my-form-part on-submit="view.save(data)">
      <label>
        Gender:
        <select ng-model="formPart.data.gender">
          <option value="male">Male</option>
          <option value="female">Female</option>
        </select>
      </label>
      <button my-form-part-submit>
        Done
      </button>
    </my-form-part>
  </my-multi-part-form>
  <div ng-if="view.part > 2">
    Complete!
  </div>
</div>

view.controller.js

视图控制器将part变量初始化为零,这是第一个表单部分的索引(表单部分存储在数组中,以 MultiPartFormController 为单位(。

angular.module('myApp')
  .controller('MyViewController', MyViewController)
;
function MyViewController($http) {
  var view = this;
  view.part = 0;
  view.save = function(data) {
    $http({
      method : 'POST',
      url    : 'https://example.com',
      data   : data
    }).then(function success(res) {
      /** handle success **/
      view.part++;
    }).catch(function error(err) {
      /** handle error **/
    });
  };
}

多部分表单指令.js

在这里,我定义 myMultiPartForm 指令并观察 part 属性,即 view.part 的插值。每当该值发生变化时(即调用view.save后成功时(,它将隐藏除view.part现在引用的表单部分之外的所有表单部分。

angular.module('myApp')
  .directive('myMultiPartForm', myMultiPartFormDirective)
  .controller('MultiPartFormController', MultiPartFormController)
;
function myMultiPartFormDirective() {
  return {
    controller  : 'MultiPartFormController',
    controllerAs: 'multiPartForm',
    link        : postLink
  };
  function postLink(scope, iElement, iAttrs, multiPartForm) {
    iAttrs.$observe('part', function (newValue) {
      angular.forEach(multiPartForm.parts, function (part, index) {
        if (index == newValue) part.show();
        else part.hide();
      });
    });
  }
}
function MultiPartFormController() {
  var multiPartForm = this;
  multiPartForm.parts = [];
}

form-part.directive.js

这就是它变得凉爽的地方。每个 myFormPart 指令在链接后阶段向其控制器添加showhide方法,然后将对其控制器的引用添加到myMultiPartForm控制器的parts数组中。这使myMultiPartForm能够操作每个myFormPart的 DOM 元素,而无需使用 jQuery 或 jqLite 遍历 DOM 树。

angular.module('myApp')
  .directive('myFormPart', myFormPartDirective)
  .controller('FormPartController', FormPartController)
;
function myFormPartDirective() {
  return {
    bindToController: {
      onSubmit: '&'
    },
    controller      : 'FormPartController',
    controllerAs    : 'formPart',
    link            : postLink,
    require         : ['myFormPart', '^myMultiPartForm'],
    scope           : true,
    template        : '<ng-transclude></ng-transclude>',
    transclude      : true
  };
  function postLink(scope, iElement, iAttrs, controllers) {
    var formPart = controllers[0];
    var multiPartForm = controllers[1];
    formPart.hide = function () {
      iElement.css({display: 'none'});
    };
    formPart.show = function () {
      iElement.css({display: 'block'});
    };
    multiPartForm.parts.push(formPart);
  }
}
function FormPartController() {
  var formPart = this;
  formPart.data = {};
}

form-part-submit.directive.js

最后,该指令将一个单击处理程序添加到它应用于的任何元素中,该元素将调用 myFormPart.onSubmit ,在此示例中,它始终是 view.save 方法(但对于每个表单部分可能是不同的函数(。

angular.module('myApp')
  .directive('myFormPartSubmit', myFormPartSubmitDirective)
;
function myFormPartSubmitDirective() {
  return {
    link: postLink,
    require: '^myFormPart'
  };
  function postLink(scope, iElement, iAttrs, formPart) {
    iElement.on('click', function() {
      if (typeof formPart.onSubmit === 'function') {
        formPart.onSubmit({data: formPart.data});
      }
    });
  }
}

操作顺序

要了解所有这些工作原理,您需要了解事情发生的顺序。以下是大纲:

  1. 多部分形式控制器实例化
  2. 形式 A 部分控制器实例化
  3. formPartSubmit 链接的 DOM 元素
  4. 形式部分 A DOM 元素链接
  5. 表单 B 部分控制器实例化
  6. 表单部分提交 B DOM 元素链接
  7. 形式B部分DOM元素链接
  8. 形式 C 部分控制器实例化
  9. 表单部分提交 C DOM 元素链接
  10. 形式C部分DOM元素链接
  11. 多部分形式 DOM 元素链接

multiPartForm控制器首先实例化,但最后链接。这意味着当调用其 postLink 函数时,其控制器已获得有关每个 formPart 所需的所有信息。然后,part值被内插,并触发第一个$observe回调。