checkbox not passing parameter when unchecked in spring mvc - spring

I am using checkbox in my application to pass one value in spring .When i checked it it is working fine but the problem lying when I unchecked it.It shows error -
WARN : org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver - Handler execution resulted in exception: Required String parameter 'isFl' is not present
here isFl is the name of checkbox which I need to pass.I search lot and got many answer applied in my program but haven't got desired result.
If anyone knowing the answer please help thanks in advance.
controller program
#RequestMapping(value = "/upload", method = RequestMethod.POST)
public ModelAndView uploadPost(#RequestParam String fileName, #Validated Template template,
#Validated TemplateBean templateBean,
#RequestParam MultipartFile file,
HttpServletRequest request,**#RequestParam String isFl**) throws Exception
{
ModelAndView model = new ModelAndView("upload");
if(isFl!=null){
addTemplate.setFl(Integer.parseInt(isFl));
}
else{
addTemplate.setFl(0);//false value
}
jsp file
<input id="checkbox" type="checkbox" **name="isFl"** value="1" >Facility letter
there is lot more things but i have only uploaded relevent to my question

Use required = false
#RequestParam(value = "isFl", required = false) String isFl

Add a hidden input with prefix '_' added to the same name as below:
<input type="hidden" name="_isFl" value="on" >

change your code like that ...HttpServletRequest request,#RequestParam Boolean isFl) because checkbox is a boolean value.
Required and String parameter 'isFl' is not present
But the parameter Boolean isFl is present in your form

Sharing my answer related to checkboxes value not being sent when it's unchecked and its value is bound to a non-boolean field (i.e., String) since this question shows as a top result.
In Spring's WebDataBinder, it has a field marker described as DEFAULT_FIELD_DEFAULT_PREFIX. This is described in Spring's WebDataBinder API.
Basically, what it does is that it sends a default value when a certain checkbox is unchecked. This is particularly useful when a checkbox is bound to a non-boolean field (i.e., String)
The default field default prefix in Spring is an exclamation mark (!).
<input id="checkbox" type="checkbox" name="isFl" value="1" >Facility letter
<input type="hidden" name="!isFl" value="0" />
The codes above will send a value of "1" if the checkbox is ticked (or checked). Otherwise, it will send "0" (value of hidden input item).
P.S.

Related

spring model binding with disabled input

sorry for a dumb question but i can't understand quite what happens, and if it is what i suspect.. well i am really at a loss.
i am using spring boot + thymeleaf + materialize css to show and validate a form.
now what i don't meet in many examples that i see is this case:
some form fields are pre-filled and should seem disabled to the client, showing their pre-filled values. this pre-filling takes place in the controller, while i handle some other request, and redirect to this view
i am binding a pojo to the form using th:object like this
<form id="register_form" action="#" th:action="#{/showform}" th:object="${userInfo}" method="post">
<div class="input-field">
<label th:text="#{label.surname}" for="surname"></label>
<input type="text" th:field="*{surname}" id="surname" th:attr="value=${userInfo.surname}" />
</div>
<div class="input-field">
<label th:text="#{label.name}" for="givenname"></label>
<input type="text" th:field="*{givenname}" id="givenname" th:attr="value=${userInfo.givenname}" disabled="disabled" />
</div></form>
and getting it in the POST handler of the controller like this:
#RequestMapping(value = {"/showform"}, method = RequestMethod.POST)
public ModelAndView submitFormPage(#ModelAttribute("userInfo") #Valid UserInfo userInfo,
BindingResult bindingResult, RedirectAttributes redir)
{
ModelAndView mview = new ModelAndView();
if (bindingResult.hasErrors())
{
// show form again with error messages
mview.addObject("userInfo", userInfo);
mview.setViewName("/showform");
}
else
{
// ...
}
return mview;
}
RedirectAttributes is there for some other reason. As you can see, there are two elements on a form, and first one is enabled, and the second disabled.
Their values are populated correctly with pre-filled values from the POJO i pass to the view via the ModelMap. i can also trace it in the GET handler.
but the ModelMap i get back from the view contains the aforementioned POJO with NULL values in place of the elements that are bound to the disabled controls. i would expect them to be populated by the contents of the value attribute, even though those controls are disabled. the enabled controls carry their values alright.
or is it just that disabled controls simply are not included in the postback? if this is the case, how would you suggest me to do it? some suggested adding an obscure CSS that would "fake" the behaviour of a disabled control. or have i missed something in the general wiring?
i think with horror of possible workarounds - but i must be doing something wrong.. th:attr was one of the workarounds i tried, but it doesn't seem to do the trick. i also tried using th:id and th:disabled but it didn't help either.
There is a misunderstanding here I think about the use of disabled.
A readonly element is just not editable, but gets sent when the
according form submits. a disabled element isn't editable and isn't
sent on submit. Another difference is that readonly elements can be
focused (and getting focused when "tabbing" through a form) while
disabled elements can't.
More detailed comparison
So to answer your question: you should opt for readonly if you want to bind your attributes to your pojo and still the user can't edit them.

How can i get the data from a second form

This is an add page. Person contains a list of addresses so when i try to add an address to that person that is not yet in the database i need to be able to retrieve the person form when an address is submitted and assign that address to that person.
<form:form action="${addAction}" modelAttribute="person">
<form:label path="name">
<spring:message text="Name"/>
</form:label>
<form:input path="name" />
... More labels and inputs
</form:form>
<form:form action="${addAddress}" modelAttribute="address">
... Labels
<input type="submit" value="<spring:message text="Add Address"/>" />
</form:form>
In my controller i have "#ModelAttribute("person") Person p" line which should retrieve the form which has "modelAttribute="person"" in it. But the person retrieved is an empty entity which i'm assuming is because the person form has to be submitted in order to retrieve the data.
#RequestMapping(value = "/person/addAddress", method = RequestMethod.POST)
public String addAddress(#ModelAttribute("person") Person p, #ModelAttribute("address") Address a, RedirectAttributes redirectAttrs) {
p.getAddresses().add(a);
redirectAttrs.addFlashAttribute("person", p);
return "redirect:/person";
}
I probably can retrieve the inputs instead of the form and use them to create a new entity with those values but if i were to do that controllers' passing attributes will be full of inputs and would look ugly. Is there a way for me to retrieve those values as a Person entity?
EDIT
Sanjay's first option is the most logical way to do it but since what i wanted to design does not fit for it i can't do it. But Sanjay's comment about making it in one form helped me so i'm selecting Sanjay's answer as the solution but here is how i fixed it
Since i had form actions saved in c:url's i changed the buttons' onclick function such that when clicked forms' action would change depending on the button and i already had corresponding controllers for the actions. For the address list inside my person i had to make a workaround by first adding an empty address to the list in my page controller and then using
<c:forEach items="${person.addresses}" varStatus="loop">
<c:if test="${loop.last}">
<form:input path="addresses[${loop.index}].street" />
...
the code above i was able to fill the previously added empty address.
I'm still in the process of fixing everything but this is the general idea of how i fixed it. Thanks for the help.
I think you may need to revisit your UI, add some hidden field etc. I can think of some solutions:
Have an "Add Address" button which appends a blank row of address into the form using JavaScript, but it doesn't submit to the server. Have the real "Submit" button at the bottom, which would submit the entire form including the person and addresses.
Have a submit button to save the person without address. Then, on a second screen, display the person, and have the address submission button.
Do the above, in reverse, if saving the Address first suits your requirements
I probably can retreieve the inputs instead of the form and use them to create a new entity with those values but if i were to do that controllers' passing attributes will be full of inputs and would look ugly. Is there a way for me to retrieve those values as a Person entity?
For cleaner code -
1.Create JSON object (say formFields) with all your form input data.
2.send formFields to server using ajax call.
3.Read formFields as String in controller
#ModelAttribute("formFields") final String formFields
4.You should have DTO matching formFields name say FormDTO.
5.convert formFields of String type to FormDTO using ObjectMapper API.
FormDTO formDto = null;
try {
ObjectMapper mapper = new ObjectMapper();
formDto = mapper.readValue(formDto, FormDTO.class);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
P.S. ObjectMapper is part of jackson-databind-2.4.4.jar

How to customize Hibernate #Size error message to indicate length of entered field

I would like to customize the error message for text fields to include the actual number of characters that were entered. I've been able to get this to work but am not satisfied with my solution, so I'm wondering what others have done to accomplish this.
Spring 4.1.2
Hibernate 4.3.10
Hibernate Validator 5.1.3
Field Annotation (limited to 10 for testing purposes - actual size is 150)
#Column(name = "NAME", nullable = false)
#Size(max=10)
private String name;
message.properties
Size.person.name=Maximum is {1} characters
JSP code
<spring:bind path="person.name">
<c:set var="nameError">${status.errorMessage}</c:set>
<c:set var="nameDisplayValue">${status.displayValue}</c:set>
<c:set var="nameCode">${status.errorCode}</c:set>
</spring:bind>
<c:if test="${fn:contains(nameCode,'Size')}">
<c:set var="nameLen">${fn:length(nameDisplayValue)}</c:set>
<c:if test="${nameLen gt 0}">
<c:set var="nameError">${nameError += " (you entered " += nameLen += ")"}</c:set>
</c:if>
</c:if>
<div class="form-group col-sm-9 <c:if test="${not empty nameError}">has-error</c:if>">
<label class="control-label" id="nameLabel" for="inputName">Name:<c:if test="${not empty nameError}"> ${nameError}</c:if></label>
<form:input type="text" size="10" class="form-control" id="inputName" placeholder="Name" path="name" autocomplete="off"/>
</div>
Output
This is ok for one field, but the form I'm working on has more than 10 fields that have size validation. Also, the size="10" setting for form:input does not appear to actually do anything, i.e., you can still enter more than 10 characters.
I know one option is to write a custom validator but that seems like overkill for what I want to do. Another would be to catch the error before the form is posted, but I'm trying to keep all of the validation server-side. Any suggestions would be greatly appreciated.
There is a good documentation about interpolating validation messages in the Hibernate documentation: Chapter 4. Interpolating constraint error messages.
If you create a file ValidationMessages.properties in the root of your classpath then you can change all validation messages there:
javax.validation.constraints.Size.message=Please enter at least {min} and at most {max} characters.
The parameters in {...} are just the attribute names of the annotation. That works for nearly every constraint. If you want to reference the validated value, you can use {validatedValue}. You can as well use Formatter to format the value:
... ${formatter.format('...', validatedValue)} ...
Unfortunately there is no format string for length.
So if you really want to have such a message for all #Size, then you will have to implement your own javax.validation.MessageInterpolator (see Custom message interpolation in the link above).
Additional remark: There is a side effect when changing the default validation message: #Size is available for collections as well. And in that case at least my message is not appropriate. I usually create a second validation message for this:
javax.validation.constraints.Size.Collection.message=Please select at least {min} and at most {max} elements.
And use that one in the constraint:
public final class ValidationMessages {
public static final String COLLECTION_SIZE =
"javax.validation.constraints.Size.Collection.message";
}
public class MyClass {
#Size(min = 1, max = 10, message = ValidationMessages.COLLECTION_SIZE)
private Collection<String> elements;
}
With a matching rule in my code style tool I ensure that I don't forget to define the message for #Size annotations on collections.

How to bind List<String> values to <select> tag in jsp without comma separated values?

First things first-
My Class-
public class StakeHolder{
private String stakeHolderName;
private Date startDate;
private Date endDate;
}
My Controller Request Mapping-
#RequestMapping(value = { "/add" }, method = RequestMethod.GET)
public String addGet(Model model) {
StakeHolder stakeholderObj = new StakeHolder();
//To be selected in drop-down for 'stakeHolderName' attribute of StakeHolder
List<String> organizationList = stakeholderObjService
.getApplicantOrganizations();
model.addAttribute("orgList", organizationList);
model.addAttribute(STAKEHOLDER_OBJ_STRING, stakeholderObj);
return STAKEHOLDER_ADD_VIEW;
}
My JSP code for drop-down -
<form:select path="stakeHolderName" name="stakeHolderSelect"
id="stakeHolderSelect" style="width:220px;" items="${orgList}" >
When i submit the form with any value from drop down I have a server-side validator to verify all the values of attributes. When there is an error in date format it returns to the same page. When the data is correct and submitted again the dropdown value gets binded to my class's 'stakeHolderName' attribute in comma separated format which is not required.
its something like
StakeHolder [stakeHolderName=,TestOrg1,TestOrg1,TestOrg1, startDate=null, endDate=null]
The original values keeps getting appended to the name each and every time it get submitted with a preceding comma. How can I get the value "TestOrg1" just once without any comma?
Appreciate the help.
try to change your drop down code to this in JSP
<form:select path="stakeHolderName">
<form:options items="${orgList}" />
</form:select>
thank you
Sorry for posting the solution so late.
The problem was found elsewhere. It was actually on the jsp. The select option had a prior radio button selection to it and on its click event i had to show a pre-filled input text box with default value for the same path variable. So when i submitted the form, it binded the value to the input text as comma separated values.
I couldn't find a solution for it through spring path variable. So i used normal html input boxes with different names and binded those values through init binder.

Checkboxes tag spring mvc and binding

I have checkboxes tag in my web application with spring mvc. Checkboxes are created from a map in controller like this:
Map demOrgs = createMap();
model.addAttribute("demOrgs", demOrgs); // example : (1, my-description)
1 --> will be value of checkbox
my-description --> will be label of checkbox
In my jsp :
<form:form commandName="myBean" method="POST" >
<form:checkboxes items="${demOrgs}" path="demOrg" element='div class="checkboxes"' />
</form:form>
My bean has only one field :
String demOrg;
When I send the form demOrg attribute has the value of checkboxes clicked, for example: (1,5,8)
I store myBean in session, when I go to the next step in my application. But when I return, I want the checkboxes were checked, still checked and isn't that way.
When the bind value of checkbox is a boolean value, allways work but I'm binding a custom value :
<input id="demOrg1" type="checkbox" value="2" name="demOrg">
<label for="demOrg1">My label description</label>
<input id="demOrg2" type="checkbox" value="3" name="demOrg">
<label for="demOrg2">My label description 2</label>
.....
Does anyone know how to do this?
thanks to all!!
What does the signature of your controller method look like? Are you including myBean as a method signature argument, annotated with #ModelAttribute ?
Something like:
#RequestMapping(......)
public String myController (#ModelAttribute MyBeanType myBean, Model model) {
Map demOrgs = createMap();
model.addAttribute("demOrgs", demOrgs);
model.addAttribute(myBean);
}
Optionally you can annotate the method parameter with #Valid as well if you are using JSR-303 bean validation .
I think the trick is to make sure your demOrg property is actually a collection. Check out the
checkbox reference here. In particular, the text that says:
Typically the bound property is a collection so it can hold multiple values selected by the user.
Though "myBean" is stored in the session, isn't it reloaded again from the database when the controller is ran?

Resources