How can i get the data from a second form - spring

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

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.

is it possible to send the entire list of objects in a submit form with spring mvc?

I am trying to modify and send a list of objects using spring MVC.
I want , when I will click in the button that triggers the form submit, in the controller, capture all the list with the objects.
Unfortunately.. I have no idea how to do this.
So far I got this:
<#form:form modelAttribute="MyObject" method="post" action"somewhere">
<#display:table list=myList id="myObject">
<#display.column title="Name">
${myObject.name}
</#display>
<#display.column title="value">
HERE I SHOULD MODIFY EVERY OBJECT WITH AN INPUT, NOT SURE IF THIS WOULD WORK
<form:input path=${myObject.value} id="value" />
</#display>
</#display>
</#form:form>
And at my controller so far I have this:
#RequestMapping (value="myurl" method = Request.POST)
public void myMethod(#ModelAttribute Object myObjects){
So here Id like to get the entire list of objects, but myObjects is null.
}
Any idea how to do this?
Thanks

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.

MVC matching ModelState keys to ViewModel collection

Is it possible to match a ViewModel property to the matching ModelState.Key value when the ViewModel is a (has a) collection?
Example: To edit a collection of viewmodel items, I am using the extension found here.
That adds a GUID to the id of the fields on the page.
example:
class Pets
{
string animal;
string name;
}
For a list of Pets, the generated html source is like this:
<input name="Pets.index" autocomplete="off" value="3905b306-a9..." type="hidden">
<input value="CAT" id="Pets_3905b306-a9...__animal" name="Pets[3905b306-a9...].animal" type="hidden">
<input value="MR. PEPPERS" id="Pets_3905b306-a9...__name" name="Pets[3905b306-a9...].name" type="hidden">
<input name="Pets.index" autocomplete="off" value="23342306-b4..." type="hidden">
<input value="DOG" id="Pets_23342306-b4...__animal" name="Pets[23342306-b4...].animal" type="hidden">
<input value="BRUTICUS" id="Pets_23342306-b4...__name" name="Pets[23342306-b4...].name" type="hidden">
So when this gets bound on post, the ModelState gets loaded with all the form fields.
In ModelSTate.Keys, there is:
Pets[23342306-b4...].name
Pets[23342306-b4...].animal
Pets[3905b306-a9...].name
Pets[3905b306-a9...].animal
Everything good so far, but I am doing some business logic validation, things like, cant add new animal if one exists with the same name. In that case, I want to be able to highlight the input field that is in error.
So if my create function fails, it will return an error/key value pair like this:
{ error = "Duplicate Name", key="name" }
So I at least will now what property caused the problem.
But since my repository functions don't know about the view field ids, how can I match the key "name" to the appropriate ModelState key (in this case, either Pets[23342306-b4...].name or Pets[3905b306-a9...].name)?
If you used the built in functionality of MVC for displaying collections (Html.DisplayFor(m => m.Pets) or Html.EditorFor(m => m.Pets)) with appropriate display/editor template, MVC would render something like this:
Pets[0].name
Pets[0].animal
Pets[1].name
Pets[1].animal
This maps to IEnumerable<Pets> and you know that first item has index of 0, second item 1 etc.
So if the second item has an error, you can set error for the ModelState key "Pets[1].name" for example.
If you are using the Html.BeginCollectionItem extension method, like I was, I was able to get around this by not using the GUID. I need the dynamic add and delete, but I was always looking up known items, persons that have an ID, which I had in my editor. So instead of using the GUID, I just assign the ID (uniqueId) in the code below. I could then find the key because I knew it was Person[234232]. Of course if you are adding new items and not displaying selected items, it might not work for you.
public static IDisposable BeginCollectionItem(this HtmlHelper html, string collectionName, string uniqueId)
{
var idsToReuse = GetIdsToReuse(html.ViewContext.HttpContext, collectionName);
string itemIndex = idsToReuse.Count > 0 ? idsToReuse.Dequeue() : uniqueId;
// autocomplete="off" is needed to work around a very annoying Chrome behaviour whereby it reuses old values after the user clicks "Back", which causes the xyz.index and xyz[...] values to get out of sync.
html.ViewContext.Writer.WriteLine(string.Format("<input type=\"hidden\" name=\"{0}.index\" autocomplete=\"off\" value=\"{1}\" />", collectionName, html.Encode(itemIndex)));
return BeginHtmlFieldPrefixScope(html, string.Format("{0}[{1}]", collectionName, itemIndex));
}

Using Beans to populate/retrieve view

I'm new to Spring and little confused of how to use beans for populating and retrieving values to/from the view.
Here is what I'm doing now.
In the controller I'm initializing two beans xxxMain.java and xxxView.java. I'm using xxxMain.java to retrieve values FROM the view and xxxView.java for pre-populating the view.
Here is my controller
#RequestMapping(value = "accounting", method = RequestMethod.GET)
public String showPage( Model model) {
XXXMain xxxMain = new XXXMain();
XXXView xxxView = new XXXView();
service.loadXXXForm(xxxMain, xxxView);
model.addAttribute("xxxMain", xxxMain);
model.addAttribute("xxxView", xxxView);
return "admin/xxx";
}
So as I'm using the xxxMain.java for retrieving I'm coding the jsp like this.
<form:form modelAttribute="XXXMain" method="post" action="/app/home/save">
</form:form>
also I'm using Spring tags, like
<form:input path="name" size="15"/>
Now, when the fields in the view are empty, all is fine, but when I have to pre-populate the fields, I'm not sure what approach to take as
<form:input path="name" size="15"/>
does not has a value attribute to populate the field. So what I have done is populate the XXXMain.java class along with the XXXView.java class with the default values, as you can see in the controller code snippet. That way values are pre-populated when view is first loaded. But I'm not sure if I'm doing the right thing by populating the xxxMain.java file which in fact should only contain the user entered values.
How can I improve this design?
Thanks a lot.
Ravi
Here is an example I wrote which might help steer you right.

Resources