I have some objects like the two below
public class SavedSearch {
String title;
ArrayList<SearchParameters> params;
}
public class SearchParameter {
String field;
int operator;
String match;
}
On the JSP page in the input form, I use
<input type="text" name="title">
and when I breakpoint inside the FormController, the SavedSearch object has title filled in.
But the ArrayList is always empty. It's not Spring's fault that it can't read my mind, but how do I indicate that field, operator and match are part of params? I tried naming them paramsField, paramsOperator, paramsMatch but no luck.
I know this is not a hard question, but I'm a bit stumped.
for binding a List you must use special wrapper instead of ArrayList: AutoPopulatingList from Spring or LazyList from Apache Commons Collections.
some examples:
using LazyList
using AutoPopulatingList
Related
I try to pass an object to th:onclick.
When I pass a string(afficherDetails() function), everything is ok
When I pass an object(afficherDetails2() function), in the called function the object seems ok but it is empty.
function afficherDetails(employee) {
console.log("afficher Details");
document.getElementById("detailledFirstNameDataLabelId").textContent = employee.firstName;
document.getElementById("detailledLastNameDataLabelId").textContent = employee.lastName;
document.getElementById("detailledAddressDataLabelId").textContent = employee.address;
document.getElementById("detailledTitleDataLabelId").textContent = employee.title;
document.getElementById("detailledManagerDataLabelId").textContent = employee.manager;
}
function afficherDetails2(name) {
console.log("afficher Details");
document.getElementById("detailledFirstNameDataLabelId").textContent = name;
}
<td><button th:data-parameter1="${employee}" th:onclick=" afficherDetails(this.getAttribute('data-parameter1')) ">details</button></label></td>
<!--td><button th:data-parameter1="${employee.firstName}" th:onclick=" afficherDetails2(this.getAttribute('data-parameter1')) ">details</button></label></td-->
</tr>
Is it a correct behavior ? Can't we pass a complex object and we can only pass simple object?
thanks for your answer
Short answer:
You can pass a complex object to a HTML attribute - but it will be reduced to a string by the object's toString() method.
Therefore, in your case, an attempt to do the following in JavaScript...
var something = employee.firstName;
...will do nothing because the function is passed a string not an object - and therefore employee.firstName will be undefined in JavaScript.
Longer answer:
Bear in mind a couple of points:
A HTML attribute expects to contain a string:
<button th:data-parameter1="SOME VALUE IN HERE" ... >
So, the attribute data-parameter1 will be populated by Thymeleaf using a string.
All Thymeleaf processing happens on the server. Thymeleaf removes all its processing directives from the template and replaces them with valid HTML. Your JavaScript does not have access to the original Java object - just to whatever representation of that object was added to the HTML by Thymeleaf.
Let's assume you use something such as:
th:data-parameter1="${employee.firstName}"
Assuming employee.firstName evaluates to a string (John) then that is what Thymeleaf will use to produce this:
data-parameter1="John"
But if you try this:
th:data-parameter1="${employee}"
Assuming employee is your custom Java bean, then Thymeleaf will call its toString() method to use as the string.
If you have not defined a toString() method in your Employee class, then the underlying Object.toString() method will be used - and you will see something like the following - a string representation of the unique object, based on the object's name and hash code:
data-parameter1="org.yourpackage.Employee#bcb8097"
You can provide your own implementation of toString() in your Employee class to provide more useful information. But it has to be a string which can be placed in a HTML attribute.
For example, if you pass an ArrayList to the button:
List<String> names = Arrays.asList("John", "Mary");
and:
th:data-parameter1="${names}"
then your HTML button will contain this:
data-parameter1="[John, Mary]"
because [John, Mary] is the result of how ArrayList has implemented its toString() method.
You can send a certain Java objects directly to JavaScript - see JavaScript serialization. But that is probably off-topic for this question.
One extra note: In the following:
th:onclick="afficherDetails(this.getAttribute('data-parameter1'));"
You are using th:onclick - but there are no Thymeleaf expressions in the attribute, so there is nothing for Thymeleaf to process. You can just use:
onclick="afficherDetails(this.getAttribute('data-parameter1'));"
Maybe a stupid question. C# 6.0 allows for string replacement using this syntax: $"string content {foo} {bar}". I would like to imitate this behavior in a class I've written for strings passed to it by default. The problem is that I am not sure how to access the public properties/variables. I am not sure if there is a way to access the properties using reflection or by passing this or this.Page to the constructor.
Figured it out:
public static object GetPropValue(object src, string propName)
{
return src.GetType().GetProperty(propName).GetValue(src, null);
}
object UID = GetPropValue(System.Web.HttpContext.Current.Handler, "UID");
I'm still new to SpringMVC (and jstl for that matter). I'm trying to populate options in a select from a list of objects. I've found a way to do it using c:forEach, but I keep thinking there HAS to be a way to make the form:options method work.
I've browsed around, and about the closest thing I can find to official documentation on the items attribute is here >> http://static.springsource.org/spring/docs/2.0.x/reference/spring-form.tld.html#spring-form.tld.options
It says the items attribute is for
"The Collection, Map or array of objects used to generate the inner 'option' tags"
My confusion is what kind of Collection, Map, or array of objects it's looking for. What format do they need to be in? Is it looking for a Collection or array of type String specifically? Can I use
List<MyObject>
and if so, what would MyObject have to have in it in order for this to be valid (i.e. methods, variables)?
Currently, when I try to use MyObject, I get an exception that says -
ConverterNotFoundException: No converter found capable of converting from type com.example.MyObject to type java.lang.String
Do I need to make a converter? Where would that go? How would that work? I've googled that error message and haven't really turned up anything specific to what I'm trying to do... (Most are results about Roo)
the MyObject class looks like this:
public class MyObject{
private String company;
private Customer customer;
private Address customerAddress;
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
public Address getCustomerAddress() {
return customerAddress;
}
public void setCustomerAddress(Address customerAddress) {
this.customerAddress = customerAddress;
}
}
and I'm trying to use it as such:
<form:select path="myObjectList">
<form:option value="0"/>
<form:options items="myObjectList" />
</form:select>
Does anyone know specifically what is incorrect about this method? Or, should I be using a
List<String>
to accomplish what I'm doing?
EDIT here's the stack trace >> http://pastebin.com/2c5XBCmG
The Spring Documentation says this about the items attribute of the form:options tag:
The items attribute is typically populated with a collection or array
of item objects. itemValue and itemLabel simply refer to bean
properties of those item objects, if specified; otherwise, the item
objects themselves will be stringified. Alternatively, you may specify
a Map of items, in which case the map keys are interpreted as option
values and the map values correspond to option labels. If itemValue
and/or itemLabel happen to be specified as well, the item value
property will apply to the map key and the item label property will
apply to the map value.
In a nutshell, if you need to use a List of your Custom Beans as the items attribute you need to use also the itemValue and itemLabel attributes. Personally, I'll prefer using Maps -LinkedHashMap instances speciffically- for populating my select tags, but that's a matter of taste.
Adapting an example from the Spring Documentation, your code should look like this:
<form:select path="commandAttribute">
<form:option value="-" label="--Please Select"/>
<form:options items="${countryList}" itemValue="company" itemLabel="company"/>
</form:select>
I'm using the company attribute as both itemValue and itemLabel, but you're free to choose the attributes that fit your requirements.
Usualy I am doing it with spring tag like this :
<springform:select path="myObjectList" id="selected_company">
<springform:option value="0" label="--- Select One ---"></springform:option>
<springform:options items="${myObjectList}" itemValue="company" itemLabel="company"></springform:options>
</springform:select>
don't forget including the namespace declaration :
xmlns:springform="http://www.springframework.org/tags/form"
I'm trying to send some data from the client side to the server, and have it processed into a file download.
I'm using a simple HTML form because I want to initialize a file download (and not AJAX).
one of the form fields is an array of items. (the other two are name and description strings).
I'm serializing this field to a string (JSON.stringify) before submitting the form.
on the server side I tried a million techniques (#ModelAttribute vs. #RequestBody, different jackson mapping bean configurations) to either convert this to a single type or to three separate types (String + String + List/Array).
the examples I found were only for AJAX...
can anyone supply a working example or a description of one?
=======
Update:
I've implemented a workaround by JSON.stringify-ing the collection and passing it in one of the inputs,
and on the server side I have:
#RequestMapping(method = RequestMethod.POST, value = "exportSectionsToExcel")
public HttpEntity<byte[]> createExcelWorkBook(#ModelAttribute ExportSectionsListForm exportSectionsListForm) {
Section[] sectionObjects = gson.fromJson(exportSectionsListForm.getSections(), Section[].class);
...
with ExportSectionsListForm object containing strings only:
public class ExportSectionsListForm {
private String name;
private String url;
private String rssUrl;
private String sections;
...
(omitting ctor, getters and setters)
additionally, I found this promising link:
http://viralpatel.net/blogs/spring-mvc-multi-row-submit-java-list/
but didn't try it - seems like I'll need to dynamically generate input elements for this to work, but it might actually be the right solution. has anyone tried this?
The #ModelAttribute tag will try to build the object based on form postings. Since you are serializing your form values to JSON, this wont work. #RequestBody simply gives you a String representing the request body. So, you could get the String representing the JSON being passed in, then demarshal the JSON using Jackson of FlexJSON (or whatever JSON library you use). I am not sure this is the best approach, though.
I would question why you need to serialize the form to JSON to begin with. Spring handles forms with Lists/Maps just fine. Simply submit the form using the #ModelAttribute, making your "array" and List, or whatever you are expecting, on the Controller. So, if I am interpreting your example correctly, my ModelAttribute would look like:
public class ExportSectionsFormBean {
private String name;
private String url;
private String rssUrl;
private List<String> sections;
/* getters/setters */
}
Then my Controller method would look like:
#RequestMapping(method = RequestMethod.POST, value = "exportSectionsToExcel")
public HttpEntity<byte[]> createExcelWorkBook(#ModelAttribute ExportSectionsFormBean exportSectionsFormBean ) {
/* Do whatever with your */
}
On the form side, using the Spring JSTL tags, simply make your "sections" fields look like:
<form:input path="sections[0]" />
<form:input path="sections[1]" />
Or, if you'd rather use HTML, then
<input type="text" name="sections[0]" id="sections0" />
<input type="text" name="sections[1]" id="sections1" />
Which is what gets generated by the above JSTL tags. As long as the values for "sections" is put in the HTTP request as 'section[#]=value', you are all set.
I have been working on the same issue. And if i have several inputs witht eh same name such as:
<input name="somename"/>
<input name="somename"/>
<input name="somename"/>
and i have a form mapped to my method like this:
#ModelAttribute("ReturnsAndExchangesForm") ReturnsAndExchangesForm returnsAndExchangesForm
and in that form i have getters and setters for a property named:
String[] somename , spring is passing those values into that array nicely!
I'm teaching myself ASP.NET MVC, and am trying to figure out where best to put a function which takes in an Models.Address instance and returns an IHtmlString instance which reads something like:
Line 1<br />
Line 2<br />
City, State
The string could be used in many places throughout my project, so I don't want to write it in one view and have to keep copy-pasting it or attaching that view: By the same logic attaching it to ViewData seems like a bad idea. However, the HtmlEncode method requires an instance of server, which means I can't add the function to the model class either.
Is there a right place to put this - some sort of shared view? (does this belong in the master?) Or am I going about this all wrong?
My current best idea is to create a ViewModel with the method public IHtmlString FormatAddress(Address address, HttpServerUtility server), but I don't know if that's the ASP.NET MVC way to do it.
As this is presentation UI logic, the best place to put it is in a HtmlHelper class.
public static class HtmlHelper
{
public static HtmlString FormatAddress (this HtmlHelper, Address address)
{
string formattedAddress = // the formatted address...
return HtmlString.Create(formattedAddress);
}
}
then, from any view you simply call:
<%= Html.FormatAddress(address) %>
I usually create something like that as an Extension Method on a HelperExtensions class and then place that class in a Helpers folder at the top level of the site.
public static class HelperExtensions
{
public static Format(this Address address, HttpServerUtility server)
{
// Do the work to format here.
}
}