AngularJS 表单验证:$dirty 值通过 ui.router 状态变化而变化
AngularJS form validation : $dirty value change through ui.router state changes
我的用例:
我有一个使用 ui-router 的多步骤表单,如下面的 plunkr 所示。我使用 ng-form 来验证 AngularJS 提供的信息,例如 $valid、$dirty 等
每次单击 "Next section" 按钮后,我都会将表单数据发送到服务器以便检索它,以防用户在完成之前 quits 表单。
如果用户提交了两次第一步,我只发送编辑过的数据(如果$dirty 值为真)。所有这些都不在 plunkr 中,我选择向您展示一个简单的表单,但我的表单可以包含一百个字段(单选框、复选框、输入、select 等)。
重现问题的步骤 (plunkr):
- 填写第 1 步并转到下一部分
- 选中 xbox 收音机并return点击数字进入第 1 步
myMultiStepForm.interests.xbox.$dirty = true
- 回到第2步
myMultiStepForm.interests.xbox.$dirty = false
为什么 $dirty 值变为 false?我猜这是因为 <ng-form>
再次显示并且所有验证数据都已重置。
有没有办法避免这种情况?或者也许 <ng-form>
以外的东西来处理字段子集的验证?
这是 plunkr : http://plnkr.co/edit/WclqVgiBvUXlsGdSCcj0?p=preview
我解决了,解决方案在下面的plunker中。
参考这个:
Note: the purpose of ngForm is to group controls, but not to be a
replacement for the tag with all of its capabilities (e.g.
posting to the server, ...).
根据 Angular Documentation for ngForm element.
我还想知道您为什么要使用许多 <ng-form>
元素。
这是您问题的唯一可能解决方案。
更新 1:
$dirty
的解释
$dirty 仅当 用户与当前范围内的特定元素交互 时才设置为真。
如果您对 true/false 问题如此挑剔
- 建议您将 $dirty 替换为 $pristine
更新 2:
为什么再次向后导航时值不正确
当您从一个表单导航到另一个表单时,该特定元素的 ng-form 的 scope 被添加到父控制器,当再次访问相同的 ng-form 时它 覆盖 现有的。
当您 link 表单或其中的任何控制器时,它始终以 $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;
})
})
我的用例:
我有一个使用 ui-router 的多步骤表单,如下面的 plunkr 所示。我使用 ng-form 来验证 AngularJS 提供的信息,例如 $valid、$dirty 等
每次单击 "Next section" 按钮后,我都会将表单数据发送到服务器以便检索它,以防用户在完成之前 quits 表单。
如果用户提交了两次第一步,我只发送编辑过的数据(如果$dirty 值为真)。所有这些都不在 plunkr 中,我选择向您展示一个简单的表单,但我的表单可以包含一百个字段(单选框、复选框、输入、select 等)。
重现问题的步骤 (plunkr):
- 填写第 1 步并转到下一部分
- 选中 xbox 收音机并return点击数字进入第 1 步
myMultiStepForm.interests.xbox.$dirty = true
- 回到第2步
myMultiStepForm.interests.xbox.$dirty = false
为什么 $dirty 值变为 false?我猜这是因为 <ng-form>
再次显示并且所有验证数据都已重置。
有没有办法避免这种情况?或者也许 <ng-form>
以外的东西来处理字段子集的验证?
这是 plunkr : http://plnkr.co/edit/WclqVgiBvUXlsGdSCcj0?p=preview
我解决了,解决方案在下面的plunker中。
参考这个:
Note: the purpose of ngForm is to group controls, but not to be a replacement for the tag with all of its capabilities (e.g. posting to the server, ...).
根据 Angular Documentation for ngForm element.
我还想知道您为什么要使用许多 <ng-form>
元素。
这是您问题的唯一可能解决方案。
更新 1:
$dirty
的解释$dirty 仅当 用户与当前范围内的特定元素交互 时才设置为真。
如果您对 true/false 问题如此挑剔
- 建议您将 $dirty 替换为 $pristine
更新 2:
为什么再次向后导航时值不正确
当您从一个表单导航到另一个表单时,该特定元素的 ng-form 的 scope 被添加到父控制器,当再次访问相同的 ng-form 时它 覆盖 现有的。
当您 link 表单或其中的任何控制器时,它始终以 $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;
})
})