I feel this should be exceedingly obvious, but so far I've failed to find an answer.
I want to have a list of strings (or an array of strings, I really don't care) get populated by form data in Struts2.
I've seen several examples of how to do indexed properties with beans, but wrapping a single string inside an object seems fairly silly.
So I have something like
public class Controller extends ActionSupport {
private List<String> strings = new ArrayList<String>();
public Controller() {
strings.add("1");
strings.add("2");
strings.add("3");
strings.add("4");
strings.add("5");
}
public String execute() throws Exception {
return ActionSupport.SUCCESS;
}
public List<String> getStrings() {
return strings;
}
public void setStrings(List<String> s) {
strings = s;
}
}
...
<s:iterator value="strings" status="stringStatus">
<s:textfield name="strings[%{#stringStatus.index}]" style="width: 5em" />
</s:iterator>
The form fields get populated with their initial values (e.g. 1, 2, etc), but the results are not properly posted back. setStrings is never called, but the values get set to empty strings.
Anybody have any idea what's going on? Thanks in advance!
I believe as you have it, your jsp code would render something like:
<input type="text" name="strings[0]" style="width: 5em" value="1"/>
<input type="text" name="strings[1]" style="width: 5em" value="2"/>
<input type="text" name="strings[2]" style="width: 5em" value="3"/>
...
Notice that the name of the field references are "strings[x]" where as you need the name to be just "strings". I would suggest something like:
<s:iterator value="strings" status="stringStatus">
<s:textfield name="strings" value="%{[0].toString()}" style="width: 5em" />
</s:iterator>
Not sure if the value attribute above may is correct, but I think something like this will get you the desired result.
Related
Let's say my controller look like this :
public class myController {
private MyCustomItem acte;
...
// getter and setter
}
and the MyCustomItem class have a Set of another class, like this
public class MyCustomItem {
private Set<AnotherClass> signataires;
...
// getter and setter
}
Finally, the AnotherClass item have some String attributes.
What I want to do is, from the view linked to my controller, set those String attributes when I submit a form, so I wrote my view.jsp like this :
<!-- some html before -->
<s:form namespace="/my/namespace" action="MyController_execute">
<s:iterator value="acte.signataires" status="signaStatus">
<s:hidden name="id" value="%{id}" />
<s:property value="collectivite.nom"/>
<s:textfield name="acte.signataires(%{#signaStatus.index}).commentaire" cssStyle="width:250px;"/>
</s:iterator>
<s:submit/>
</s:form>
Afte I submitted the form, in my controller if I try to get some values from my Set<> acte.signataires, they are null :
for (AnotherClass signataire : acte.getSignataires()) {
System.out.println(signataire.getCommentaire()); // this print NULL
}
any help on this ? Is my jsp mapping bad ? I also tried a very simple syntax like <s:textfield name="commentaire" cssStyle="width:250px;"/> but it won't work either
Do you need the property signataires to be a Set ?
I suggest to you to use an ArrayList so that you can access each element by the index (signataires[0], signataires[1], etc...).
Using an ArrayList then you could do in this way:
<s:form namespace="/my/namespace" action="MyController_execute">
<s:iterator value="acte.signataires" status="signaStatus">
<s:hidden name="id" value="%{id}" />
<s:property value="collectivite.nom"/>
<INPUT type="text" name="acte.signataires[<s:property value="%{#signaStatus.index}"/>].commentaire" cssStyle="width:250px;"/>
</s:iterator>
<s:submit/>
</s:form>
I have an enum like this
public enum CheckboxFeature {
Option1(" choose this"),
Option2(" or this"),
Option3(" maybe this"),
Option4(" lastly this");
#Getter
private final String text;
public static CheckboxFeature fromName(String v) {
for (CheckboxFeature c: CheckboxFeature.values()) {
if (c.name().equalsIgnoreCase(v)) {
return c;
}
}
throw new IllegalArgumentException(v);
}
}
This shows the four options as checkboxes in the web view
<form:checkboxes items="${features}" path="enabledFeatures" itemLabel="text" delimiter="<br/>"/>
How can I translate these options? I use fmt:message for the rest of the translations in the web view.
I have tried
Option1(" <fmt:message key=\"text.test\"/>"),
and
Option1(" ${option1}"),
with
<fmt:message key="text.select" var="option1"/>
in the .jsp.
Neither of them work, so it seems it can't work this way. What is the correct way of translating the strings? Ideally using the fmt:message and i18n resources (lang.properties files) that are in place and working on the rest of the servlet?
Optimally, you get the resource key from the enum, and look that up.
public enum CheckboxFeature {
Option1("label.option1.key"),
Option2("label.option2.key"),
Option1("label.option3.key"),
Option2("label.option4.key");
private final String key;
[...]
I don't know how to nest a l10n lookup in the itemLabel attribute, so I would write something like:
<c:forEach items="Options.values()" var="current">
<form:checkbox path="selectedOptions" value="${current.name()}"/> <fmt:message key="${current.getKey()}"/>
</c:forEach>
1、CheckboxFeature add method like:
public static List<String> getAllCheckboxFeature(String v) {
return Arrays.asList(Option1.getText(),...Option4.getText());
}
2、than use the jstl like:
<c:forEach items="${options}" var="option">
<input type="checkbox" ="${option}">
</c:forEach>
I am using struts 2 and I have set up my code like this:
Action class:
public class OrderDetailAction extends BaseActionSupport {
private Collection<ShippingAddress> shippingAddressList;
<the getters and setters here>
private Collection<ShippingAddress> billingAddressList;
<the getters and setters here>
public String displayCreate() {
LOGGER.info("DISPLAY CREATE CALLED");
populateForiegnFields();
LOGGER.info("populate foreign fields done calling");
return SUCCESS;
}
private void populateForiegnFields(){
LOGGER.info("ENTERED POPULATE FOREIGN FIELDS");
ShippingAddressService shippingAddressService = ServiceFactory.getInstance().getShippingAddressService();
shippingAddressList = shippingAddressService.getShippingAddresss();
if(shippingAddressList == null) {
LOGGER.info("shipping address list IS NULL");
} else {
LOGGER.info("shipping address list IS NOT NULL. CONTENTS:");
}
getSession().put("shippingAddressList", shippingAddressList);
billingAddressList = shippingAddressService.getShippingAddresss();
if(billingAddressList == null) {
LOGGER.info("billingAddressList IS NULL");
} else {
LOGGER.info("billingAddressList IS NOT NULL. CONTENTS:");
}
getSession().put("billingAddressList", billingAddressList);
}
And the snippet of my Create Order Detail JSP is:
<s:form>
<div class="form-group">some other fields</div>
<div class="form-group">
<s:select label="SHIPPINGADDRESSID" list="shippingAddressList" listKey="ID" listValue="ID" name="shippingAddress" ></s:select>
</div>
<div class="form-group">
<s:select label="BILLINGADDRESSID" list="billingAddressList" listKey="ID" listValue="ID" name="billingAddress" ></s:select>
</div>
<input class="btn btn-success" type="submit" name="action:createOrderDetail" value="submit" id="displayCreateOrderDetail_createOrderDetail"/>
<input class="btn btn-default" type="submit" name="action:getOrderDetails" value="cancel" id="displayOrderDetail_getOrderDetails" />
</s:form>
The error I am getting is this:
tag 'select', field 'list', name 'shippingAddress': The requested list
key 'shippingAddressList' could not be resolved as a
collection/array/map/enumeration/iterator type
But what confuses me, especially after I looked up this error on other posts
people suggested that the shippingAddressList may never have been instantiated but when I checked the log files that I wrote above, it was not null and at one point, I also logged the values from shippingAddressList.
Are there other reasons I could be getting this error?
Thank you in advance.
First Remove Collection and instead use List.
private List<ShippingAddress> shippingAddressList;
<the getters and setters here>
private List<ShippingAddress> billingAddressList;
<the getters and setters here>
I am not sure why you are putting these two list on session. They will already be on value stack.
I believe your ShippingAddress class have ID property.
Oh boy so here is the error I was making. To make sure people don't run into this headache:
my getters and setters for my shippingAddressList and my billingAddressList were as follows:
get**s**hippingAddressList(); set**s**hippingAddressList()
and
get**b**illingAddressList(); set**b**illingAddressList()
The issue here was that the casing was not proper. Because it was not proper camel case, struts was never able to call the getters and setters.
I'm trying to create a list of objects from form inputs. The objects are the same but their values may differ, it's essentially a menu.
I'm still getting to grips with Spring/Thymeleaf which is adding some level of complexity to what feels like a simple task.
I've a class for the menu, a simple POJO, there is then a list of these defined as a data member in the bean itself:
private ArrayList<GuestMenuOptions> guestMenus;
I've read many posts, tried many things and am on the verge of softly resting my head against the table.
I've had several errors, most of which either tell me that the list cannot be found or that the list is empty - it's currently in stable condition where the list, no matter what I try, will not be populated, even when I load in default values...unfortunately my debugger has died which is not helping.
Any help is appreciated. thank you
EntryController:
#RequestMapping(method=RequestMethod.GET, value="/")
public String indexPage(Model model) {
model.addAttribute("childMenuOptions", generateChildMenus());
//not sure if this is neccesary...
ArrayList<GuestMenuOptions>guestMenus = new ArrayList<>();
GuestMenuOptions ad1 = new GuestMenuOptions();
GuestMenuOptions ad2 = new GuestMenuOptions();
guestMenus.add(ad1);
guestMenus.add(ad2);
GuestContactBean ctb = new GuestContactBean();
ctb.setGuestMenus(guestMenus);
model.addAttribute("guestContactBean", ctb);
model.addAttribute("formBackingBean", new FormBackingBean());
return "index";
}
Form:
<form modelAttribute="guestBean" class="contact_form" name="rsvp" role="form" th:object="${formBackingBean}" th:action="#{/sendRsvp}" method="post">
<div class="row">
<div class="form-group">
<select name="ad1Starter" id="starterMealAdult1">
<option value="!!!">-Starter-</option>
<option th:field="${guestContactBean.guestMenus[0].starter}" th:each="entry : ${adultMenuOptions.get('starter').entrySet()}" th:value="${entry.key}" th:text="${entry.value}">
</option>
</select>
</div>
<input type="submit"guest name="submit" class="btn default-btn btn-block" value="Send RSVP">
RequestController:
#RequestMapping(value = "/sendRsvp", method = RequestMethod.POST)
public String sendRsvp(#ModelAttribute("guestContactBean") GuestContactBean guestContactBean,
#ModelAttribute("guestMenus") ArrayList<GuestMenuOptions>menus,
BindingResult result) throws MessagingException {
smtpMailSender.send(guestContactBean);
return "thanksMessage";
}
Beans:
FormBacking is POJO with no reference to the menus at all.
GuestMenuOptions is the same with just starter, desert members
guestContactbean has not much more going on, basic fields with the addition of the list of GuestMenuOptions
private String numberOfAdults;
private String eventAttending;
private ArrayList<GuestMenuOptions> guestMenus;
public ArrayList<GuestMenuOptions> getGuestMenus() {
return guestMenus;
}
EDIT:
The field that populates the drop downs in working fine, it's declared as private Map<String, Map<String, String>> adultMenuOptions;
private Map<String, Map<String, String>> childMenuOptions;
they are then built in the controller so that each may have several options under 'starter', 'main' and desert' for example:
starter.put("salmon", "Smoked Salmon");
starter.put("pate", "Chicken Liver Pate");
this is then populating both the value and text of the dropdown.
If I could save the state of this Map and pass it back to the controller instead, that would also be fine but I wasn't able to why then spawned the creation of the there wrapper list.
Please revisit http://www.thymeleaf.org/doc/tutorials/2.1/thymeleafspring.html#dropdownlist-selectors. It should be as simple as
class Animal {
int id;
String name;
}
then in your template:
<select th:field="*{animalId}">
<option th:each="animal : ${animals}"
th:value="${animal.id}"
th:text="${animal.name}">Wireframe</option>
</select>
I think your code is all over the place and you're mixing up menu selection with menu item types.
Could someone please help me find out why my attempt to bind Collection to the form in Spring MVC is not working?
Here is how my object looks like -
public class TestObj {
private Integer testNumber;
private String home;
private String destination;
}
Here is my form object that contains list of above object -
public class TestForm {
private List<TestObj> testList;
//contains getter and setter for testList
}
In my controller, I have implemented formBackingObject method -
public class MyController extends SimpleFormController {
public MyController() {
setCommandClass(TestForm.class);
setCommandName("testForm");
}
protected Object formBackingObject(HttpServletRequest request) throws Exception {
if (isFormSubmission(request)) {
testForm = (TestForm) super.formBackingObject(request);
//THIS ALWAYS RETURNS NULL ON FORM SUBMISSION
List<TestObj> testList = testForm.getTestList();
} else {
//load initial data using hibernate. TestObj is hibernate domain object.
List<TestObj> testList = myService.findTestList();
testForm = new TestForm(testList);
}
return testForm;
}
Here is my JSP snippet -
<form:form commandName="testForm" method="post">
<c:forEach items="${testForm.testList}" var="testvar" varStatus="testRow">
<tr>
<td>
<form:hidden path="testList[${testRow.index}].home" />
<c:out value="${testvar.home}" />
</td>
<td>
<form:input path="testList[${testRow.index}].destination" />
</td>
</tr>
</c:forEach>
<tr><td><input type="submit"></td></tr>
</form:form>
While the first time I load the data shows up fine on the form, when I press submit button the control goes to the formBackingObject method and the isFormSubmission returns true. However, when I get the command object using super.formBackingObject(request), it returns the form object with the testList value as null. I am unable to figure out why this simple case is not working?
I will really appreciate any help in getting this to work.
Are you using Spring 3? If so, you should take a look at this post.
With respect to list processing and object binding, take a look at this post.
Try using the following code. May be that can solve your problem.
private List<TestObj> operationParameterses = LazyList.decorate(new ArrayList<TestObj>(), FactoryUtils.instantiateFactory(TestObj.class));
It won't return you all null list.
Hope that helps you.
Cheers.
I guess my understanding of formBackingObject method must be wrong. I removed that method from the implementation, used referenceData for initial form load and onSubmit to process it on submit. This works fine and does get collection in the form back as expected.
Thanks all for the help though.