Using dynamic variable in each - java

<th:block th:each="someData, index : ${someData.from.somewhere}">
<th:block th:each="image : ${images.foo0bar}">
<img th:src="${image}"/>
</th:block>
<hr/>
</th:block>
I want 0 in images.foo0bar to be replaced by index
How do I do something like th:each="image : ${images.foo + index + bar}"

You can use Thymeleaf's preprocessor to execute a getter based on a concatenated string:
__${...}__
For example:
<th:block th:each="someData, iterstat : ${someData}">
<th:block th:with="imageField=|images.foo${iterstat.index}bar|">
<th:block th:each="image : ${__${imageField}__}">
<img th:src="${image}">
</th:block>
</th:block>
</th:block>
In the above approach, the th:with="imageField=..." is used to build the string you need:
images.foo0bar
images.foo1bar
... and so on...
That imageField variable is then used with the Thymeleaf preprocessing syntax to handle it as a field name in your images object.
UPDATE
My solution above had a mistake, as originally written. Instead of this:
__${imageField}__
It should be this:
${__${imageField}__}
In other words, I forgot to wrap the pre-processor results in a Thymeleaf expression - so that the actual objects in each list (of image URLs) are retrieved.
I corrected this, above.
For backgound, here is the test data I used for the Thymeleaf model:
List<String> someData = Stream.of("abc", "def", "ghi")
.collect(Collectors.toList());
List<String> a = Stream.of("1", "2", "3")
.collect(Collectors.toList());
List<String> b = Stream.of("4", "5", "6")
.collect(Collectors.toList());
List<String> c = Stream.of("7", "8")
.collect(Collectors.toList());
Images images = new Images();
images.setFoo0bar(a);
images.setFoo1bar(b);
images.setFoo2bar(c);
Map<String, Object> model = new HashMap<>();
model.put("someData", someData);
model.put("images", images);
And my Images class contains these 3 fields:
private List<String> foo0bar;
private List<String> foo1bar;
private List<String> foo2bar;
Just a suggestion...
The Java objects which support this appear to be a bit convoluted, behind the scenes.
You have a collection of someData which you do not directly access, except to iterate through a count of its contents.
You then use this count to build a field name, so you can executed the related getter - and iterate through that collection of image URLs, in a completely different (seemingly unrelated) object.
Just as a suggestion: If you re-arrange your Java data, you could avoid this Thymeleaf complexity.

Related

Wicket : Add a list to a datatable

I have a list of object to display in a table with wicket.
Those object are composed of a String and an Array of String.
My problem is that i don't know how to add this array into my table. And second, i have some css that I need to apply to each of my String of the array, so each of them have to be on a different div/span/li.
Can it be a good idea to concatenate all those elements and add the "div" manually ?
Thank you for your help :)
I have been to obssesed with using a datatable. By using a list in a list it work just fine !
JAVA :
ListView<Profil> listProfil = new ListView<Profil>("listProfils", profils) {
protected void populateItem(ListItem<Profil> item) {
Profil tmpProfil = item.getModelObject();
item.add(new Label("libelle", tmpProfil.getLibelle()));
item.add( new ListView("listChamps", tmpProfil.getChamps()) {
protected void populateItem(ListItem item) {
item.add(new Label("libelleChamps", item.getModel()));
}
});
}
});
And the associate HTML template :
<tr wicket:id="listProfils">
<div class="row">
<td class="col-xs-4 col-md-3 col-lg-3 text">
<span wicket:id="libelle"></span>
</td>
<td class="col-xs-7 col-md-8 col-lg-8 text" colspan="3">
<span wicket:id="listChamps">
<span wicket:id="libelleChamps"
class="label label-default badge badge-tag" >Champs</span>
</span>
</td>
</div>
</tr >
As a good practice in Wicket, to build a Table in HTML that is being fed from a List, you need the following elements:
HTML
<table wicket:id="yourWicketIdOfDataTableObject">[table]
</table>
JAVA
A POJO (pojoObject) that represents each element (o regiser) of your table
A DataProvider (dataProviderObject) class that extends from SortableDataProvider<pojoObject, String>
You need to override the iterator(), size() and model() methods according to your needs.
A List<IColumn<pojoObject,String>> columnsObject
The above object will represent the colums of your table.
You could add columns as follows:
columnsObject.add(new PropertyColumn<pojoObject,String>(new Model<String>("nameOfTheColum"),pojoObjectPropertyName))
A DefaultDataTable tableObject:
DataTable<pojoObject, String> = new DefaultDataTable("yourWicketIdOfDataTableObject", columnsObject, dataProviderObject, NumOfColumns)
The above object will represent the table.
As you might see pojoObject wraped by columnsObject and dataProviderObject, and these two will be wrapped by tableObject at the end. Your array will be accessed in the iterator() method of the dataProviderObject, because it needs to retrieve the iterator of the list; The pojoObject that represent the each element of your actual list will be necessary (in case you don't have one yet)
At the end, you only need add tableObject in their Wicket Parent, as any other Wicket Component.

Looping through a list of lists using JSTL

I have a list of courses depending on school code. This list of courses is added to another list, making it a list-of-lists.
Action Class:
private List<String> schoolList;
private List<String> socList;
private List<String> sobList;
private List<String> sodList;
private List<String> genlist;
private List<List<String>> courseList = new ArrayList<List<String>>();
#Override
public String execute() {
FacultyManager fm = new FacultyManager();
schoolList = fm.getColumn("school_description", "school");
genlist = fm.getCoursesBySchoolCode("GEN");
sobList = fm.getCoursesBySchoolCode("SOB");
socList = fm.getCoursesBySchoolCode("SOC");
sodList = fm.getCoursesBySchoolCode("SOD");
courseList.add(genlist);
courseList.add(sobList);
courseList.add(socList);
courseList.add(sodList);
return SUCCESS;
}
JSP:
<c:forEach var="school" items="${schoolList}" varStatus="ctr">
<ul>
<li>${school}
<ul>
<c:forEach var="course" items="${courseList}">
<li>${course}</li>
</c:forEach>
</ul>
</li>
</ul>
</c:forEach>
Output
How do I make it so the output is:
GENERAL EDUCATION
DEPARTMENT OF GENERAL EDUCATION
SCHOOL OF BUSINESS
BSBA - FINANCIAL MANAGEMENT
BSBA - MARKETING AND ADVERTISING
... and so on.
You are iterating the whole list of courses in all schools over and over again, thus repeating the same output as if you called courseList.toString() method multiple times.
You should instead iterate over a concrete list of courses in a current school, which most likely (but nowhere stated in your question) depends on the current iteration index of the outer <c:forEach> loop. This is in turn captured in the index property of the exported ctr variable (that is zero-based) of the school list iteration index.
Thus, you should iterate over a specific list of the courseList list, depending on the current school. You can do this by calling courseList.get(ctr.index), assuming you are on EL2.2+.
This all yields:
<c:forEach var="school" items="${schoolList}" varStatus="ctr">
<ul>
<li>${school}
<ul>
<c:forEach var="course" items="${courseList.get(ctr.index)}">
<li>${course}</li>
</c:forEach>
</ul>
</li>
</ul>
</c:forEach>
That said, List<List<String>> does not sound as a good model choice. For instance, if you change insertion order you'll get the wrong courses in your view. Map<String, List<String>> construct fits better your domain model as it can be used to map school name to a list of course names unambiguously.
Another option to consider seriously is the usage of objects (you are doing OOP in the end). You should turn away from plain strings and move into objects domain. To start, investigate the following class hierarchy:
public class Course {
//...
private School school;
//...
}
public class School {
//...
private List<Course> courses;
//...
}
If you are trying to iterate the list inside the list , you can achive it by
<c:forEach var="school" items="${schoolList}" varStatus="ctr">
<ul>
<li>${school}
<ul>
<c:forEach var="course" items="${school}">
<li>${course}</li>
</c:forEach>
</ul>
</li>
</ul>
</c:forEach>
You need to iterate the inner list from the list you pass it to the jsp.
Update
In the case if you are using Map<String, List<String>> , you can iterate it as
<c:forEach var="school" items="${schoolList}" varStatus="ctr">
<ul>
<li>${school.key}
<ul>
<c:forEach var="course" items="${school.value}">
<li>${course}</li>
</c:forEach>
</ul>
</li>
</ul>
</c:forEach>
You can use the key and value to get the values from the Map

Pass java map from JSTL/JSP to JavaScript methods

We have couple of related drop downs where results of one drop down relate to other dropdown.
We have a mapping defined for what to select when in the form of map-of-map, like this;
Map<String,Map<String,String>> topics = new HashMap<String, Map<String,String>>();
Map<String,String> ds = new HashMap<String, String>();
ds.put("Array", "Array");
ds.put("LL", "LL");
topics.put("DS", ds);
Map<String,String> algo = new HashMap<String, String>();
algo.put("BS", "BS");
algo.put("Sorting", "Sorting");
topics.put("Algorithm", algo);
Map<String,String> phil = new HashMap<String, String>();
phil.put("phil1", "phil1");
phil.put("phil2", "phil2");
topics.put("Philosophy", phil);
Map<String,String> others = new HashMap<String, String>();
others.put("others", "others");
topics.put("Others", others);
As per the above map, when "DS"is selected, we want to display "Ă„rray"and "LL". Similar is the case with other mappings.
I pass this map to JSP and use JSTL to render the options. While making decision to call JS to populate subsequent drop-down, I want to change it to JSON.
I want to pass specific map of the selected option to the JS method and populate subsequent drop down.
Is converting to JSON the only way? If yes, how about passing it from the controller? If we don't pass it from the controller, what are the cleaner ways to do it in JSP itself?
JSP Block is as follows:
<div>Subject</div>
<select name="topic" onchange="callJavaScriptMethodWithMapOfSelectedComponent(mapOfSelectedValue)");">
<c:forEach var="entry" items="${topics}">
<option value="${entry.key}">${entry.key}</option>
</c:forEach>
</select>
<select name="college">
<option value="default">Select Subject</option>
</select>
Depending on the values selected in first drop down, we need to populatevalues in second drop down.
JS method would take map of selected value in first drop down and populate second one.
function setOptions(chosen) {
var selbox = document.myform.college;
selbox.options.length = 0;
if (chosen == " ") {
selbox.options[selbox.options.length] = new Option('Please select one of the options above first',' ');
}
selbox.options[selbox.options.length] = new Option('//Choosen from the map passed','oneone');
}
}
First off I think you better change it so that topics is a Map < String, List < String > >, that'd make more sense since it's a single depth hierarchy.
Next up you have the choice of either converting the map into JSON and using eval to fill an object in javascript, or manually transverse the map keys and add them to the object, it all depends on the tools you have at hand to serialize the map into JSON server side (You can use new JSONObject(topics); from json.org) then just eval the json into a variable on Javascript.

Loop through HashSet and HashMap in JSP and print the result

I want to do the below thing in JSP starting from for loop- I just want to loop HashSet and HashMap and print the result
private static HashMap<Long, Long> histogram = new HashMap<Long, Long>();
private static Set<Long> keys = histogram.keySet();
for (Long key : keys) {
Long value = histogram.get(key);
System.out.println("MEASUREMENT, HG data, " + key + ":" + value);
}
I am working with Spring MVC, so I added these two things in my model
model.addAttribute("hashSet", (keys));
model.addAttribute("histogram", (histogram));
And in my JSP page, I was doing something like this to emulate the above JAVA code but it was giving me an exception that something is wrong in my JSP page.
<fieldset>
<legend>Performance Testing:</legend>
<pre>
<c:forEach items="${hashSet}" var="entry">
Key = ${entry.key}, value = ${histogram}.get(${entry.key})<br>
</c:forEach>
</pre>
<br />
</fieldset>
Exception I got-
Caused by: javax.el.PropertyNotFoundException: Property 'key' not found on type java.lang.Long
at javax.el.BeanELResolver$BeanProperties.get(BeanELResolver.java:195)
at javax.el.BeanELResolver$BeanProperties.access$400(BeanELResolver.java:172)
at javax.el.BeanELResolver.property(BeanELResolver.java:281)
at javax.el.BeanELResolver.getValue(BeanELResolver.java:62)
Can anyone help me out with this?
You don't need to make use of keySet to access the values in the HashMap. When you iterate over HashMap using <c:forEach..>, you get back the EntrySet, for which you can use: - EntrySet#getKey() and EntrySet#getValue() directly: -
<c:forEach items="${histogram}" var="entry">
Key = ${entry.key}, value = ${entry.value}<br>
</c:forEach>

Order of request.getParameterNames()

How do I get all the parameterNames in an HTML form in
the same sequence?
Example:
If the form contains FirstName, LastNameand Age
The output should appear exatcly in the same sequence
I have tried using the following but this shifts the
order of the output:
Enumeration paramNames = request.getParameterNames();
while(paramNames.hasMoreElements()) {
String paramName = (String) paramNames.nextElement();
out.print(paramName);
}
I don't think there's nothing in the HTTP spec that forces browsers to send parameters in the order they appear in the form. You can work it around by prefixing a number to the name of the parameter like:
FirstName --> 0_FirstName
LastName --> 1_LastName
...
After that you could basically order the elements by the prefix. It is an ugly solution but it is the only way to do it. Something like:
// Assuming you fill listOfParameters with all the parameters
Collections.sort(listOfParameters, new Comparator<String>() {
int compare(String a,String b) {
return Integer.getInt(a.substring(0,a.indexOf("_"))) -
Integer.getInt(a.substring(0,b.indexOf("_")))
}
});
for (String param : listOfParameters) {
// traverse in order of the prefix
}
By the way - does it really matters the order in which you receive the parameters ?
None of the answers here really did answer my question. A HttpServletRequest saves all it's parameters in a HashMap, and a HashMap has NO ORDER. So, I saved the order of the parameters in an ordered ArrayList and saved it in a HttpSession, so I could retrieve the order of the parameters by querying the ArrayList (that was saved in the session) and achieve what I wanted!
request.getParameterNames () uses HashMap internally to store the name value pairs of form fields. There is no order maintained in this. if you need this in order then , some sort of naming convention for form parameters to control the order of retrieval.
SortedSet temp = new SortedSet();
Enumeration enumeration = request.getParameterNames();
while (enumeration.hasMoreElements())
{
temp.add((String)enumeration.nextElement());
}
Updated: You can use sorted set for that. Note that you must have all the parameters with different names (in this case it is most likely). Write any prefix as your parameter name.
Example:
<input type="text" name="1step">
<input type="text" name="2step">
Then in java code you can write:
SortedSet ss = new TreeSet();
Enumeration<String> enm = request.getParameterNames();
while(enm.hasMoreElements()) {
String pname = enm.nextElement();
}
Iterator i = ss.iterator();
while(i.hasNext()) {
String param = (String)i.next();
String value = request.getParameter(param);
}
HTML or Jsp Page
<input type="text" name="1UserName">
<input type="text" name="2Password">
<input type="text" name="3MobileNo">
<input type="text" name="4country">
and so on...
then in java code
SortedSet ss = new TreeSet();
Enumeration<String> enm=request.getParameterNames();
while(enm.hasMoreElements()){
String pname = enm.nextElement();
ss.add(pname);
}
Iterator i=ss.iterator();
while(i.hasNext()) {
String param=(String)i.next();
String value=request.getParameter(param);
}

Categories

Resources