Here my test setup:
The Model:
package models;
import javax.persistence.Entity;
import play.db.jpa.Model;
@Entity
public class Item extends Model {
public String propertyA;
public String propertyB;
public String getFullName() {
return this.propertyA + " - " + this.propertyB;
}
}
The Controller:
package controllers;
import play.*;
import play.mvc.*;
import java.util.*;
import models.*;
public class Application extends Controller {
public static void index() {
List<Item> allItems = Item.findAll();
render(allItems);
}
public static void save(List<Item> items) {
if (items == null) {
Logger.info("no items");
} else {
for (Item item : items) {
Logger.info("item: %s",item);
}
Logger.info("-------");
}
index();
}
}
The view:
#{extends 'main.html' /}
#{set title:'Home' /}
#{form @Application.save()}
Select Items:
<div>
<select name="items" style="width: 200px;" multiple="multiple" size="10">
#{list items:allItems, as: 'item'}
<option value=${item.id} >${item.fullName}</option>
#{/list}
</select>
</div>
<input type="submit" value="Save" />
#{/form}
When I select two Items in the Select box, I get the following Log output:
06:22:20,560 INFO ~ -------
06:22:26,991 INFO ~ item: null
06:22:26,991 INFO ~ item: null
It looks like play maps the selection to a List of null
objects. Even when I change the view to:
<option value=${item} >${item.fullName}</option>
I get null
values.
But when I change the controller to:
public static void save(List<Long> items) {
...
}
I at least get a List of correct Ids.
How can I change this, so that play creates the correct mapping for my items. I prefer to get List<Item>
instead of List<Long>
(here I have to perform queries to geht the List of Items).
BR, Rene
Update:
If I run:
curl -d "items[0].id=3&items[0].propertyA=bla&items[0].propertyB=blo&items[1].id=4" http://localhost:9000/application/save
Wich does a POST with the above parameters, I get:
A02:39:53,072 INFO ~ item: bla - blo
02:39:53,072 INFO ~ item: null - null
02:39:53,072 INFO ~ -------
Like this it works, but I do not see how I could change the view, so that it posts the above parameters :-(
Update 2:
With the help from Felipe I got it to work. This Controller Method has to be added:
@Before(only = {"save"})
static void parseParams() {
String[] items = params.getAll("items");
params.remove("items");
for (int i = 0; i < items.length; i++) {
Item item = Item.findById(Long.parseLong(items[i]));
params.put("items[" + i + "].id", items[i]);
params.put("items[" + i + "].propertyA", item.propertyA);
params.put("items[" + i + "].propertyB", item.propertyB);
}
}
This is a binding problem, play is not binding the long[] parameter it receives.
Going from play's documentation: http://www.playframework.org/documentation/1.2.3/controllers#objectbinding
You would need to change the name on your select to items.id
It's possible that it will not work, as play expects the list to have the index as items[i].id
...
Anyway, if this doesn't solve your problem, you can make a custom bind, but that option is good mostly when you're going need this bind in a lot of places, if you're doing it only once, there's no reason to not do the query as you said in the end of the post. (Play will make this query to do this binding, so you don't lose or win any performance by doing it yourself)
Update Something along the lines:
@Before(only={"save"})
static void parseParams() {
String[] itens = params.getAll("items")
for (int i=0;i<itens.length;i++) {
params.put("items["+i+"].id",itens[i])
}
}
Should work.
Another way is javascript, but it's harder and more bug prone.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With