8

我的用例:

我有一个使用 ui-router 的多步骤表单,如下面的 plunkr 所示。我使用 ng-form 来验证 AngularJS 提供的信息,例如 $valid、$dirty 等。

每次单击“下一部分”按钮后,我将表单数据发送到服务器以检索它,以防用户在完成之前退出表单。

如果用户两次提交第一步,我只发送编辑后的数据(如果 $dirty 值为 true)。所有这些都不在 plunkr 中,我选择向您展示一个简单的表单,但我的表单可以包含一百个字段(单选、复选框、输入、选择等)。

重现问题的步骤(plunkr):

  1. 填写步骤 1 并转到下一部分
  2. 选中 Xbox 收音机并单击数字返回第 1 步 myMultiStepForm.interests.xbox.$dirty = true
  3. 回到第 2 步 myMultiStepForm.interests.xbox.$dirty = false

为什么 $dirty 值改为 false?我猜这是因为<ng-form>再次显示并且所有验证数据都被重置。

有没有办法避免这种情况?或者可能不是<ng-form>处理字段子集的验证?

这是 plunkr:http ://plnkr.co/edit/WclqVgiBvUXlsGdSCcj0?p=preview

4

2 回答 2

3

当您链接表单或其中的任何控制器时,它始终以$pristine. 原因是模型formData.type只是有一些值,angular 无法知道这些值是默认状态,来自服务器,还是之前用户交互的结果;它们很简单string或没有附加这种元数据的东西。

要实现您想要的,您必须手动跟踪状态转换中的$dirty状态,并$setDirty在需要时应用到表单上。

这是一个简单的示例,向表单步骤页面添加一个控制器,它在退出时保存表单状态(到共享服务实例,您也可以添加它resolve)并在构造时恢复它。电流formPage通过默认参数值注入,因此同一控制器可用于所有步骤。

// router:

$stateProvider.state('form.interests', {
  url: '/interests',
  controller: 'FormStepController',  
  params: { formPage: 'interests'}
  templateUrl: 'form-interests.html'
})

// state

angular.value("formDirtyState", {});

// controller

angular.controller("FormStepController", function($scope, formDirtyState, $stateParams) {
  var formPage = stateParams.formPage;

  for(var formField in $scope.myMultiStepForm[formPage]) {
    if(formDirtyState[formPage] && formDirtyState[formPage][formField])
      $scope.myMultiStepForm[formPage][formField].$setDirty()
  }
    

  $scope.$on("$destroy", function() { 
    for(var formField in $scope.myMultiStepForm[formPage])
      formDirtyState[formField] = $scope.myMultiStepForm[formPage][formField].$dirty;
  })

})

于 2016-10-10T14:13:20.090 回答
2

我解决了,解决方案在下面的 plunker 中。

参考这个:

注意:ngForm 的目的是对控件进行分组,而不是用它的所有功能(例如发布到服务器,...)来替代标签。

根据ngForm 元素的 Angular 文档

我也想知道你为什么要使用很多<ng-form>元素。这是解决您的问题的唯一可能解决方案。

Plunker Modified

更新1:

$脏的解释

仅当用户与当前范围内的特定元素交互时,$dirty才设置为 true。

如果你对真/假问题如此特别

  • 建议您将$dirty替换为$pristine

更新 2:

为什么再次导航返回时值不正确

当您从一个表单导航到另一个表单时,该特定元素的 ng-form 的范围被添加到父控制器中,当再次访问相同的 ng-form 时,它会覆盖现有的那个。

于 2016-10-10T11:41:30.257 回答