I've seen a lot of questions around here about implementing dynamic forms in jQuery or other javascript libraries, and I think I managed to get up and running in setting up a dynamic form for my test purposes.
My question is whats the best practice in naming my form fields and processing them on the server side.
I am trying to implement a contact like form where the user can add multiple phone numbers (and types) as well as multiple addresses (and types) something similar to the code below, this is the code block that will be duplicated dynamically.
<div id="phones">
<label>Phone Number</label><input type="text" name="phone1" value="" />
<label>Type</label><input type="text" name="type1" value="" />
</div>
Then I will have a +/- link or button to add another phone or remove a phone. When I submit the form, whats the best way to handle the combo of name/type
Should I have the names like indicated above with a postfix of an id like phone1 / type1 or should I use the array naming like phone[] / type[] and match the pairs on the server according to the index.
I am using java (not sure if it makes a difference if it is java or php or whatever) but what would be a best practice of doing this.
Thanks
Square brackets with indexes seem to be what most frameworks expect, but it does completely depend on your framework. In the Java world, given that there are about a million different frameworks, you have to start from what your framework expects, and adapt your Javascript code appropriately.
The only Java framework I'm familiar enough with to know the answer is Stripes, and it would want square brackets. If your bean had a property
private List<Address> addresses;
public List<Address> getAddresses() { return addresses; }
public void setAddresses(final List<Addresses>) { this.addresses = addresses; }
then the inputs would need names like "addresses[0].street1", "addresses[0].street2", etc. When you add a new block for a new address, you'd have the same fields with "1" instead of "0".
A different Java framework, however, might do things in completely different ways.
In your case, you should number the field specifically. Don't use array naming convention, which caused me big headache in the past.
If you use arrays, you will run risk of mismatching type and phone values when parameters are missing. Some browsers simply ignore empty values.
To help server retrieve all the parameters, I normally put the number of fields in a hidden field. For the form will look like this,
<div id="phones">
<input type-"hidden" name="count" value="3" />
<ul>
<li>
<label>Phone Number</label><input type="text" name="phone1" value="" />
<label>Type</label><input type="text" name="type1" value="" />
</li>
<li>
<label>Phone Number</label><input type="text" name="phone2" value="" />
<label>Type</label><input type="text" name="type2" value="" />
</li>
<li>
<label>Phone Number</label><input type="text" name="phone3" value="" />
<label>Type</label><input type="text" name="type3" value="" />
</li>
</ul>
</div>
Related
I have a handler like
#RequestMapping(...)
public String get(#RequestParam List<Cmd> rows) {...}
And I use Spring forms tags to generate the inputs. So the JSP code
<c:forEach var="i" begin="0" end="${fn:length(rows)}" >
<form:input path="rows[${i}].name" />
...
</c:forEach>
generates
<input name="rows[0].name" value="...' />
This is all good, but I also want to allow the user to add rows dynamically, so template inputs needs to be written. However, neither name="rows.name" nor name="rows[].name" works, so I have to write code to generate indexes, which is annoying.
Am I missing something here? Is there any better way to do this?
Edit:
BTW, I tried to use Javascript to generate name="rows[n].name" dynamically, but it becomes a problem if the user deletes a row in the middle. A code to rewrite all the indexes seems to be unreasonable.
You can use Javascript to insert new input. Spring generates following
<input name="rows[0].name" value="...' />
Now you want user to enter new value then your Javascript code should generate following line
<input name="rows[1].name" value="...' />
and suppose user wants one more value then,
<input name="rows[2].name" value="...' />
Remember to handle index while generating inputs using Javascript.
try this,
<form:input path="${rows[i].name}" />
instead of
<form:input path="rows[${i}].name" />
I'm stuck in a situation where I've an input element in a JSP where user enters tags. E.g. java, foo, bar, anotherTag..etc
<c:url var="saveUrl" value="/create" />
<form:form modelAttribute="myAttribute" method="POST"
action="${saveUrl}">
<form:input path="myTitle" />
<form:textarea path="myPost" />
<form:input type="text" id="tagInput"path="???" />
<input type="submit" value="create" />
</form:form>
Now in my domain model corresponding to this input is a
private List<Tag> listOfTags
How to bind a csv to a List. If I enter listOfTags in the path(which is wrong for obvious reasons), I get incorrect binding exception.
How do I convert(or bind) a csv to a List so that the Spring form is submitted properly and the listOfTags get the tags entered in the JSP.
What is the best way to achieve it?
Please help.
I'm not sure but try this. Do a simple html input :
<input type="text" id="tagInput" name="myTags" />
And then in your controller do something like :
#RequestMapping(value="/create", method=RequestMethod.POST)
public void create(..., #ModelAttribute("myAttribute") MyClass myAttribute,
#RequestParam("myTags") String myTags, ...) {
...
myAttribute.setListOfTags(Arrays.asList(myTags.split(",")));
...
}
Note : for more generic ways to bind and convert objects, you may want to take a look at PropertyEditors and Converters.
I suggest try to bind it directly to listOfTags property. And to make it work just add contructor with one argument of String type (or define static method valueOf(String)) to Tag class.
Pretty sure you could do something like this:
<c:forEach var="i" begin="1" end="10">
<form:input type="text" path="listOfTags" />
</c:forEach>
Where you get the user to enter each tag into a separate text input. This is because Spring will automagically bind multiple inputs with the same form name to a List, when it does its binding.
You could use some jQuery sugar to only show one or two and then provide a widget to show more tag inputs. Or even write some cool JS to populate the inputs from a single text input just like StackOverflow does when you add tags.
we have a list of domain objects needing to be edited on an html page. For example, the command & domain objects:
class MyCommand {
List<Person> persons;
}
class Person {
String fname;
String lname;
}
Then, the HTML I expect to have the Spring MVC tag libraries generate is like this:
<form>
<input name="persons[0].fname"> <input name="persons[0].lname"><br/>
<input name="persons[1].fname"> <input name="persons[1].lname"><br/>
<input name="persons[2].fname"> <input name="persons[2].lname"><br/>
...
<input name="persons[n].fname"> <input name="persons[n].lname"><br/>
</form>
But can't see how to express this using the Spring Form Tag Libraries (using Spring 2.5.6.). I want to use the tag libraries so that it takes care of binding existing values to the tags for editing (when they're there).
Any tips?
There isn't a way to simply have the Spring Form Tags generate the whole list based on the collection (it will do this for the options in a select box, but that's the only collection-based expansion I'm aware of). However, you can still use the Spring Form Tags within a loop like so:
<c:forEach var="person" varStatus="loopStatus" items="myCommand.persons">
<form:input path="persons[${loopStatus.index}].fname" /> <form:input path="persons[${loopStatus.index}].lname" /><br />
</c:forEach>
I'm developing a Java/Spring web application. The problem I'm currently facing is that I'd like to have message from message.resources shown as an attribute in an HTML.
<input type="submit" name="login" value="login" />
So instead of the hardcoded value "login" I need to the value of
<spring:message code="general.submit" /> as the value attribute of that input tag. As the pages are all xml, it's no option to nest tags like
<input type="submit" name="login" value="<spring:message code="general.submit" />" />
as it does not compile. I could, of course, read the value in the Java controller and use a JSTL variable to display the value, but I think it would be too hackish and complicated, especially for pages with large amount of submit buttons. Is there some kind of elegant way of accomplishing what I want to do?
Use <spring:message> to store the value in a var, then reference that var using EL, e.g.
<spring:message code="general.submit" var="submitText"/>
<input type="submit" name="login" value="${submitText}" />
Does JSP or any related lightweight technology like JSTL perform HTTP POST "data grouping", or support form element "indexing" in the way PHP does?
For example, you can create an HTML form with the following inputs:
<input type="text" name="person[1][name]" />
<input type="text" name="person[1][age]" />
<input type="text" name="person[2][name]" />
<input type="text" name="person[2][age]" />
... and PHP will parse that into a nested associative array automatically. Do JSP, Java Servlets, or any related spec or tool provide this kind of translation out of the box?
The goal is to submit multiple "record groups" in a single form, and process them server-side in JSP or a Servlet.
Requirements:
The functionality cannot rely on JavaScript
No full frameworks like Spring, Struts, or the like
I'm trying to avoid reinventing the wheel with my own naming convention and manual String parsing / Regex
Related Links:
How this is accomplished in PHP
Another PHP example from ONLamp
Try this,
<input type="text" name="personNames" />
<input type="text" name="personAges" />
<input type="text" name="personNames" />
<input type="text" name="personAges" />
You should consider to create input fields using a loop, you don't need to postfix the name even. and get parameter values like this in your servlet,
String[] names = request.getParameterValues("personNames");
String[] ages = request.getParameterValues("personAges");
It will come in the same order as defined in your HTML. Then loop over it like below,
for( String name : names) {
System.out.println(name);
}