s:checkbox fieldValue always true in validation before submitting

匿名 (未验证) 提交于 2019-12-03 09:18:39

问题:

I am using Struts 2 <s:checkbox /> in my form processing, along with AngularJS and jQuery.
Before submitting, I need validation and until now we do this in the project:

When we press Submit button, this function is called:

$scope.processForm('myForm', '<s:url value="/form/validate.action" />',                               '<s:url value="/form/save.action" />');

, where processForm(formId, validateUrl, submitUrl) is a function defined by us:

$scope.processForm = function(form, validateUrl, submitUrl) {     window.scroll(0,0);     ProccessFormService.processStandarForm(form, validateUrl, submitUrl); };

And furthermore, we have processStandarForm() defined in a global service:

angular.module('ourApp').controller('myFormCtrl',                                      function($scope, $modal, ProccessFormService) { ... }

In service:

(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)                 }             }         }            }, }

Basically, we are submitting twice the form, firstly for validation, then for submitting.

What I don't understand, is that if I debug in action class, in the function of validate(), the boolean value of <s:checkbox /> is always true, but in submit() function, boolean values are submitted correctly, according to they are checked/not checked. Checkboxs are like this:

<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>

I understand that, the value submitted is fieldValue="xxx" in <s:checkbox />, and by default is true. So I did this to change the fieldValue of every checkbox before the page is loaded. Although all the script are executed, nothing changed. I still get all true in validation.

$(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");         }     }); });

So, how can I get right boolean values not only in submitting, but also in validation?? Is the Angular service wrongly written ? I really doubt that but I am not able to figure out the question.

回答1:

Suspected that data is not serialized properly that used with angular $http().

If you want to emulate $.param() that used in jQuery you should use built-in serializer $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 paramSerializer 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'     }   });  });

Another ways to convert from $.param to angular you can find in Convert $.param in angularjs



回答2:

You've probably removed (or messed up: uncheckedValue=true) something useful from your Interceptor Stack, like the 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.



回答3:

I have figured out the problem myself. It lies in here:

var data = this.form2Object(form);

Noted that form2Object(form) is another function, I dug more into this and found this function is serializing the form, converting it to object manually and is not processing <input type="checkbox" /> correctly.

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; }

So I have changed it to this:

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; }

But, reading @Roman C's answer, I realized that maybe it's better to serialize the form with build-in functions. So I accepted his answer.



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!