Checkboxes tag spring mvc and binding - spring

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?

Related

retain model values in case of error and showing same thymeleaf template

As per my understanding, model attributes are associated with every request and they can not survive multiple requests, until we add them as flashAttributes.
I have a simple controller method which shows a couple of options to user to select from. However, those options are being attached to thymeleaf template using model attributes.
<div class="input-group mb-3" th:each="ingredient : ${recipes.ingredients}">
<div class="input-group-prepend">
<div class="input-group-text">
<input aria-label="Checkbox for following text input" name="ingredient"
th:value="${ingredient.name}" type="checkbox">
</div>
<input aria-label="Text input with checkbox" class="form-control" disabled
th:value="${ingredient.name + ' ' + ingredient.price + 'Rs.'}"
type="text">
</div>
assume "recipes" as model attribute here, which was injected to modelMap inside the controller.
when bean validation fails, below line exectutes.
if (errors.hasErrors()) return "selectItem";
and selectItem template is re-rendered, but whatever model attributes I have set inside previous controller vanishes.
I have solved this using a #ModelAttribute method inside the same controller to set model attributes for every HTTP requests for the specific controller(until it is not in controllerAdvice for global effect).
I am being confused if I am on right way || is there any elegant way to achieve this.
Setting Model attribute for every request is kind of overhead, when I want them to be available for handful of request mappings.
When you say:
selectItem template is re-rendered, but whatever model attributes I
have set inside previous controller vanishes.
You mean that when the page reloads due to validation errors, your model attributes are no longer existing and Thymeleaf probably returns an error, because it cannot find them, correct?
If this is the case, then you have to manually prepare the same model attributes within the if statement (i.e. adding them to your MapModel):
if (errors.hasErrors()) {
map.addAttribute("recipes", recipes);
return "selectItem";
}
Alternatively, if you need this model attribute also on other pages in your controller, you can reduce code duplication by declaring a method with the ModelAttribute annotation, which will add this attribute to all models in your controller:
#ModelAttribute("recipes")
public Recipes loadRecipes() {
// get list of Recipes
return list;
}

Bind dropdown value to a bean in Thymeleaf

I have a drop downdown box and trying to bind the selected account number to fromAccount inside the transfer bean.
I am seeing the value as null in the controller.
<select class="form-control" th:field="${customer.transferBean.fromAccount}">
<option
th:each="fromAccount: ${customer.accountBean}"
th:value="${fromAccount.accountNum}"
th:text="${fromAccount.accountNum}" ></option>
</select>
controller code:
#PostMapping("/accounttransfer")
public String accountTransfer(#Valid CustomerBean customerBean, BindingResult bindingResult, Model model)
Not sure what i am missing. I am using spring boot and thymeleaf for html.
Thanks.
You are using wrong syntax
"th:field="${customer.transferBean.fromAccount}"
for specifying bind field, you should use *{} not ${} and only combined with th:object on parent or ansestor level.
More details on bindingm you can find in Thymeleaf docs

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.

Thymeleaf, Spring nested backing object is not binding the values on form submit

I have a nested object and I'm using it as a model for a form.
public AgeBracketSet implements Serializable{
private String id;
private List<AgeBracket> ageBrackets;
/* Getters and Setters */
}
I have successfully bound all the properties of this object to the form and I can visualize their values when the view state is rendered. Here's a simplified version of how I'm doing it with Thymeleaf. Essentially, I loop through the items of the list and get their attributes.
<form id="bracketForm" role="form" th:action="${flowExecutionUrl}" th:object="${ageBracketSet}" method="post">
<input th:id="'bracketSet_'+*{id}" th:field="*{id}" />
<th:block th:each="bracket,loop : *{ageBrackets}" th:id="'bracket_'+${bracket.id}">
<input th:id="'fromAge_'+${bracket.id}" th:field="*{ageBrackets[__${loop.index}__].fromAge}" />
<input th:id="'toAge_'+${bracket.id}" th:field="*{ageBrackets[__${loop.index}__].toAge}" />
</th:block>
</form>
However, when I make changes in the form and submit it, the model remains unchanged. I have confirmed this by debugging the service that receives the form data. The model does not have the changes made in the form. Am I doing anything wrong here?
I am embarrassed to say I've found the solution. The values simply weren't posted to the webflow for a lack of a 'name' attribute in each input. Using the same dynamically generated ID as a name did the job, and the bindings were correct for each item of the list. Like this:
<input th:id="'fromAge_'+${bracket.id}" th:name="'fromAge_'+${bracket.id}" th:field="*{ageBrackets[__${loop.index}__].fromAge}" />
Thanks to everyone who took the time to read this silly post. I'll be more careful next time ;)

how to do binding in Spring annotated request parameter?

i have a controller that is using annotation for request mapping and requestParam.
the controller is working fine. However when submitting a command object with array, spring will crap out saying array index out of bound. i am guessing there is something wrong with binding but don't know how to fix it.
to be more specific, in eclipse i would set debugger at the beginning of the controller, and when submitting the form (by hitting a input submit button) eclipse debugger will not trigger and i will see array index out of bound error in console.
the controller is something like this:
#RequestMapping(value = {"/internal/pcsearch.dex", "/external/pcsearch.dex"},
method = {RequestMethod.POST, RequestMethod.GET})
public ModelAndView executeProductCatalogSearch(
HttpServletRequest request,
#RequestParam(value = "cat" ,required = false) String cat,
#RequestParam(value = "brand" ,required = false) String brand,
#ModelAttribute("command") ProductCatalogCommand cmd
){
[edit]
and the jsp is like:
<form name="pForm"
id="pForm"
action="<c:url value="psearch.dex"><c:param name="cat" value="${cat}"/></c:url>"
method="POST"
style="display:inline;">
...
...
<c:forEach var="model" items="${models}" varStatus="modelLinkStatus">
<script>
var modelImg<c:out value="${modelLinkStatus.index}"/>Src = '<c:out value="${model.altModelImage}"/>';
</script>
<spring:bind path="command.models[${modelLinkStatus.index}].modelSkusDisplayed">
<input type="hidden" name="<c:out value="${status.expression}"/>" id="<c:out value="${status.expression}"/>" value="<c:out value="${status.value}"/>"/>
</spring:bind>
<spring:bind path="command.updateCartButton">
<input type="submit" value="<spring:message code="orderEntryMessages.ecatalog.button.addToCart" text="Add to Cart" htmlEscape="yes" />" name="<c:out value="${status.expression}"/>" id="<c:out value="${status.expression}"/>" class="sub_buttons"/>
</spring:bind>
...
and the command object declare the model array as:
private List<ModelLink> models = new ArrayList<ModelLink>();
where modelLink is a custom ds.
the first foreach tag handle the the model command object and the 2nd part is the submit button i clicked on.
i think you should use AutoPopulatingList as models to bind list to view and controller. for example please refer link. This might resolve your problem of index.

Resources