s:checkbox fieldValue 在提交前的验证中始终为真
s:checkbox fieldValue always true in validation before submitting
我在表单处理中使用 Struts 2 <s:checkbox />
,以及 AngularJS 和 jQuery.
在提交之前,我需要验证,直到现在我们在项目中这样做:
当我们按下提交按钮时,这个函数被调用:
$scope.processForm('myForm', '<s:url value="/form/validate.action" />',
'<s:url value="/form/save.action" />');
哪里
processForm(formId, validateUrl, submitUrl)
是我们定义的函数:
$scope.processForm = function(form, validateUrl, submitUrl) {
window.scroll(0,0);
ProccessFormService.processStandarForm(form, validateUrl, submitUrl);
};
此外,我们在全局服务中定义了processStandarForm()
:
angular.module('ourApp').controller('myFormCtrl',
function($scope, $modal, ProccessFormService) {
...
}
在役:
(function() {
angular.module('ourApp').factory('ProccessFormService', ['$http', function($http) {
processStandarForm: function(form, validateUrl, submitUrl) {
this.processForm(form, validateUrl, submitUrl);
},
processForm: function(form, validateUrl, submitUrl, success) {
if ((typeof form) == 'string') {
form = document.getElementById(form);
}
var data = this.form2Object(form);
var ctrl = this;
if (data) {
if (validateUrl) {
$http({
method : 'POST',
url : validateUrl,
data : $.param(data), // pass in data as strings
headers : { 'Content-Type': 'application/x-www-form-urlencoded' }
// set the headers so angular passing info as form data (not request payload)
}).success(function() {
if (!success) {
form.action = submitUrl;
form.submit();
} else {
ctrl.submitAjaxForm(submitUrl, data, success)
}
});
} else if (submitUrl) {
if (!success) {
form.action = submitUrl;
form.submit();
} else {
this.submitAjaxForm(submitUrl, data, success)
}
}
}
},
}
基本上,我们提交了两次表单,首先是验证,然后是提交。
我不明白的是,如果我在操作class中调试,在validate()
的函数中,<s:checkbox />
的布尔值是始终为真,但在 submit()
函数中,布尔值被正确提交,根据它们被 checked/not 选中。 复选框是这样的:
<div class="col-sm-12 form-checkbox">
<s:checkbox name = "myForm.married"
ng-model = "checkboxModel"
value = "<s:property value='%{myForm.married}'/>"
ng-change = "submitCheckbox();"
ng-init = "checkboxModel= %{myForm.married}"
theme = "simple"
ng-disabled = "anotherFunction()" />
</div>
我了解到,提交的值为<s:checkbox />
中的fieldValue="xxx"
,默认为true。所以我这样做是为了在加载页面之前更改每个 checkbox
的 fieldValue
。尽管所有脚本都已执行,但没有任何变化。我在验证中仍然完全正确。
$(document).ready(function(){
$( "input:checkbox" ).each(function(){
var checkbox = $(this);
var checked = checkbox.prop("checked");//sera false/true
if (checked == true){
checkbox.prop("fieldValue", "true");
} else {
checkbox.prop("fieldValue", "false");
}
});
});
那么,我怎样才能在提交和验证中获得正确的 boolean
值呢? Angular服务写错了吗?我真的很怀疑,但我无法弄清楚这个问题。
您可能已经从您的拦截器堆栈中删除(或搞砸了:uncheckedValue=true
)一些有用的东西,例如 Checkbox Interceptor:
org.apache.struts2.interceptor.CheckboxInterceptor
is in the
defaultStack. It checks each form parameter submitted to the action
and if it finds one with a prefix of _checkbox
it inserts a value for
a parameter whose name is derived from the suffix to _checkbox if it
does not exist. The default value inserted is false but this can be
changed by setting the uncheckedValue parameter on the interceptor.
This means that a checkbox can be accompanied by a hidden input with
the same name but a prefix of _checkbox
so that if the checkbox is not
checked on the form the action will still receive a value rather than
the default HTML action of not providing a value for unchecked
checkboxes.
怀疑与angular$http()
一起使用的data
序列化不正确。
如果你想模拟 jQuery 中使用的 $.param()
,你应该使用内置序列化程序 $httpParamSerializerJQLike
。
Alternative $http
params serializer that follows jQuery's param()
method logic. The serializer will also sort the params alphabetically.
To use it for serializing $http
request parameters, set it as the
paramSerializer
property:
$http({
url: myUrl,
method: 'GET',
params: myParams,
paramSerializer: '$httpParamSerializerJQLike'
});
It is also possible to set it as the default paramSerialize
r in the
$httpProvider
.
Additionally, you can inject the serializer and use it explicitly, for
example to serialize form data for submission:
.controller(function($http, $httpParamSerializerJQLike) {
//...
$http({
url: myUrl,
method: 'POST',
data: $httpParamSerializerJQLike(myData),
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
});
});
另一种从 $.param
转换为 angular 的方法,您可以在 Convert $.param in angularjs
中找到
我自己解决了这个问题。它位于此处:
var data = this.form2Object(form);
注意到 form2Object(form)
是另一个函数,我对此进行了更多研究,发现 这个函数正在序列化表单,手动将其转换为对象,并且没有正确处理 <input type="checkbox" />
.
form2Object: function(form) {
var data = null;
if ((typeof form) == 'string') {
form = document.getElementById(form);
}
if (form) {
data = new Object();
for (var i = 0; i < form.elements.length; i++) {
if ( (form.elements[i].tagName.toUpperCase() == 'INPUT') || form.elements[i].tagName.toUpperCase() == 'TEXTAREA') {
//here it considers `<input type="checkbox" />` as normal `<input />`, and will submit its `value=xxx` in validation, and it will always be `true` due to `<s:checkbox />`.
//But it will be correct in real submission because before that, we don't go through here.
data[form.elements[i].name] = form.elements[i].value;
} else if (form.elements[i].tagName.toUpperCase() == 'SELECT') {
data[form.elements[i].name] = form.elements[i].value;
}
}
}
return data;
}
所以我改成了这样:
form2Object: function(form) {
var data = null;
if ((typeof form) == 'string') {
form = document.getElementById(form);
}
if (form) {
data = new Object();
for (var i = 0; i < form.elements.length; i++) {
if ( (form.elements[i].tagName.toUpperCase() == 'INPUT' &&
form.elements[i].type.toUpperCase() != 'CHECKBOX')
||
form.elements[i].tagName.toUpperCase() == 'TEXTAREA') {
data[form.elements[i].name] = form.elements[i].value;
} else if (form.elements[i].tagName.toUpperCase() == 'SELECT') {
data[form.elements[i].name] = form.elements[i].value;
} else if (form.elements[i].tagName.toUpperCase() == 'INPUT' &&
form.elements[i].type.toUpperCase() == 'CHECKBOX') {
var checkbox = $(form.elements[i]);
if (checkbox.prop("checked") == true){
data[form.elements[i].name] = true;
} else if (checkbox.prop("checked") == false){
data[form.elements[i].name] = false;
}
}
}
}
return data;
}
但是,阅读@Roman C 的回答,我意识到也许最好用内置函数序列化表单。所以我接受了他的回答。
我在表单处理中使用 Struts 2 <s:checkbox />
,以及 AngularJS 和 jQuery.
在提交之前,我需要验证,直到现在我们在项目中这样做:
当我们按下提交按钮时,这个函数被调用:
$scope.processForm('myForm', '<s:url value="/form/validate.action" />',
'<s:url value="/form/save.action" />');
哪里
processForm(formId, validateUrl, submitUrl)
是我们定义的函数:
$scope.processForm = function(form, validateUrl, submitUrl) {
window.scroll(0,0);
ProccessFormService.processStandarForm(form, validateUrl, submitUrl);
};
此外,我们在全局服务中定义了processStandarForm()
:
angular.module('ourApp').controller('myFormCtrl',
function($scope, $modal, ProccessFormService) {
...
}
在役:
(function() {
angular.module('ourApp').factory('ProccessFormService', ['$http', function($http) {
processStandarForm: function(form, validateUrl, submitUrl) {
this.processForm(form, validateUrl, submitUrl);
},
processForm: function(form, validateUrl, submitUrl, success) {
if ((typeof form) == 'string') {
form = document.getElementById(form);
}
var data = this.form2Object(form);
var ctrl = this;
if (data) {
if (validateUrl) {
$http({
method : 'POST',
url : validateUrl,
data : $.param(data), // pass in data as strings
headers : { 'Content-Type': 'application/x-www-form-urlencoded' }
// set the headers so angular passing info as form data (not request payload)
}).success(function() {
if (!success) {
form.action = submitUrl;
form.submit();
} else {
ctrl.submitAjaxForm(submitUrl, data, success)
}
});
} else if (submitUrl) {
if (!success) {
form.action = submitUrl;
form.submit();
} else {
this.submitAjaxForm(submitUrl, data, success)
}
}
}
},
}
基本上,我们提交了两次表单,首先是验证,然后是提交。
我不明白的是,如果我在操作class中调试,在validate()
的函数中,<s:checkbox />
的布尔值是始终为真,但在 submit()
函数中,布尔值被正确提交,根据它们被 checked/not 选中。 复选框是这样的:
<div class="col-sm-12 form-checkbox">
<s:checkbox name = "myForm.married"
ng-model = "checkboxModel"
value = "<s:property value='%{myForm.married}'/>"
ng-change = "submitCheckbox();"
ng-init = "checkboxModel= %{myForm.married}"
theme = "simple"
ng-disabled = "anotherFunction()" />
</div>
我了解到,提交的值为<s:checkbox />
中的fieldValue="xxx"
,默认为true。所以我这样做是为了在加载页面之前更改每个 checkbox
的 fieldValue
。尽管所有脚本都已执行,但没有任何变化。我在验证中仍然完全正确。
$(document).ready(function(){
$( "input:checkbox" ).each(function(){
var checkbox = $(this);
var checked = checkbox.prop("checked");//sera false/true
if (checked == true){
checkbox.prop("fieldValue", "true");
} else {
checkbox.prop("fieldValue", "false");
}
});
});
那么,我怎样才能在提交和验证中获得正确的 boolean
值呢? Angular服务写错了吗?我真的很怀疑,但我无法弄清楚这个问题。
您可能已经从您的拦截器堆栈中删除(或搞砸了:uncheckedValue=true
)一些有用的东西,例如 Checkbox Interceptor:
org.apache.struts2.interceptor.CheckboxInterceptor
is in the defaultStack. It checks each form parameter submitted to the action and if it finds one with a prefix of_checkbox
it inserts a value for a parameter whose name is derived from the suffix to _checkbox if it does not exist. The default value inserted is false but this can be changed by setting the uncheckedValue parameter on the interceptor.This means that a checkbox can be accompanied by a hidden input with the same name but a prefix of
_checkbox
so that if the checkbox is not checked on the form the action will still receive a value rather than the default HTML action of not providing a value for unchecked checkboxes.
怀疑与angular$http()
一起使用的data
序列化不正确。
如果你想模拟 jQuery 中使用的 $.param()
,你应该使用内置序列化程序 $httpParamSerializerJQLike
。
Alternative
$http
params serializer that follows jQuery'sparam()
method logic. The serializer will also sort the params alphabetically.To use it for serializing
$http
request parameters, set it as theparamSerializer
property:$http({ url: myUrl, method: 'GET', params: myParams, paramSerializer: '$httpParamSerializerJQLike' });
It is also possible to set it as the default
paramSerialize
r in the$httpProvider
.Additionally, you can inject the serializer and use it explicitly, for example to serialize form data for submission:
.controller(function($http, $httpParamSerializerJQLike) { //... $http({ url: myUrl, method: 'POST', data: $httpParamSerializerJQLike(myData), headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }); });
另一种从 $.param
转换为 angular 的方法,您可以在 Convert $.param in angularjs
我自己解决了这个问题。它位于此处:
var data = this.form2Object(form);
注意到 form2Object(form)
是另一个函数,我对此进行了更多研究,发现 这个函数正在序列化表单,手动将其转换为对象,并且没有正确处理 <input type="checkbox" />
.
form2Object: function(form) {
var data = null;
if ((typeof form) == 'string') {
form = document.getElementById(form);
}
if (form) {
data = new Object();
for (var i = 0; i < form.elements.length; i++) {
if ( (form.elements[i].tagName.toUpperCase() == 'INPUT') || form.elements[i].tagName.toUpperCase() == 'TEXTAREA') {
//here it considers `<input type="checkbox" />` as normal `<input />`, and will submit its `value=xxx` in validation, and it will always be `true` due to `<s:checkbox />`.
//But it will be correct in real submission because before that, we don't go through here.
data[form.elements[i].name] = form.elements[i].value;
} else if (form.elements[i].tagName.toUpperCase() == 'SELECT') {
data[form.elements[i].name] = form.elements[i].value;
}
}
}
return data;
}
所以我改成了这样:
form2Object: function(form) {
var data = null;
if ((typeof form) == 'string') {
form = document.getElementById(form);
}
if (form) {
data = new Object();
for (var i = 0; i < form.elements.length; i++) {
if ( (form.elements[i].tagName.toUpperCase() == 'INPUT' &&
form.elements[i].type.toUpperCase() != 'CHECKBOX')
||
form.elements[i].tagName.toUpperCase() == 'TEXTAREA') {
data[form.elements[i].name] = form.elements[i].value;
} else if (form.elements[i].tagName.toUpperCase() == 'SELECT') {
data[form.elements[i].name] = form.elements[i].value;
} else if (form.elements[i].tagName.toUpperCase() == 'INPUT' &&
form.elements[i].type.toUpperCase() == 'CHECKBOX') {
var checkbox = $(form.elements[i]);
if (checkbox.prop("checked") == true){
data[form.elements[i].name] = true;
} else if (checkbox.prop("checked") == false){
data[form.elements[i].name] = false;
}
}
}
}
return data;
}
但是,阅读@Roman C 的回答,我意识到也许最好用内置函数序列化表单。所以我接受了他的回答。