Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to submit a list of Objects in Play Framework

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);
    }
}
like image 988
reen Avatar asked Nov 04 '22 14:11

reen


1 Answers

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.

like image 129
Felipe Avatar answered Nov 09 '22 11:11

Felipe