0

I have an Offer object in Play models, which can have on or more OfferLines, so I have

@Required
@ManyToOne
public Offer offer;

on OfferLine

and

@OneToMany(mappedBy="offer", cascade= CascadeType.ALL)
public List<OfferLine> offerLines;

on Offer.

When I open my form, I have the following to populate things for rendering

Offer myOffer = new Offer();
myOffer.offerFrom = currentUser;
myOffer.targetSwag = targetSwag;
myOffer.offerTo = targetSwag.Owner;
myOffer.offerLines = new ArrayList<OfferLine>();

for (Swag swagline : mySwag)
{
    OfferLine offerLine = new OfferLine();
    offerLine.quantity=0;
    offerLine.swag = swagline;
    myOffer.offerLines.add(offerLine);
}

myOffer.save();
renderArgs.put("myOffer",myOffer);
render();

and then finally, my form looks like this (indentation notwithstanding...)

#{form @submitOffer(), id:'submitOffer'}
<table border="1">
    <thead>
    <tr>
        <th width="30" align="left">ID</th>
        <th width="80" align="left">Swag</th>
        <th width="30" align="left">Quantity</th>
    </tr>
    </thead>
    <tbody>
    #{list items:myOffer.offerLines, as:'offerline'}

    <tr>
    <td height="32" width="30"><input type="text" id="offerline.id" 
name="offerline.id" value="${offerline.id}"/></td>
    <td height="32" width="80">
        ${offerline.swag.Name}
    </td>
    <td height="32">
        <input class="field" id="offerline.quantity" name="offerline.quantity" type="number" min="0" max="${offerline.swag.Quantity}" value="${offerline.quantity}"/>
    </td>
</tr>
    #{/list}
    </tbody>
</table>

When I submit, I call a method like this...

public static void submitOffer(Integer amountRequested, Offer myOffer)
{
    myOffer.save();
    System.out.println("Requested " + amountRequested);
    System.out.println("My offer coming out " + myOffer.toString());


    renderJSON(myOffer);

}

but my Offerlines are not in the JSON, i.e., they don't seem to be passed back to in the Offer object. How can I edit and save a list of OfferLines related to an Offer in the one screen?

[Update] I tested the MyOffer object that's passed to the form and it has the offerlines, it just doesn't come back out again..

    {
  "offerLines": [
    {
      "swag": {
        "Name": "Test Swag",
        "Description": "Big ol' test swag",
        "Quantity": 10,
        "Owner": {
          "username": "robcowell",
          "password": "REDACTED",
          "email": "REDACTED",
          "fullname": "Rob Cowell",
          "isAdmin": true,
          "isActive": true,
          "Photo": {
            "bucket": "REDACTED",
            "key": "d5654f8f-0cd0-45a2-a77f-3edda01feca0",
            "contentLength": 0
          },
          "hasChangedPassword": true,
          "id": 1
        },
        "Photo": {
          "bucket": "REDACTED",
          "key": "b0774667-a32a-4508-81ba-cdb84ebc689f",
          "contentLength": 0
        },
        "id": 52
      },
      "quantity": 0,
      "id": 134
    },
    {
      "swag": {
        "Name": "Swag 2",
        "Description": "Swag 2",
        "Quantity": 5,
        "Owner": {
          "username": "robcowell",
          "password": "REDACTED",
          "email": "REDACTED",
          "fullname": "Rob Cowell",
          "isAdmin": true,
          "isActive": true,
          "Photo": {
            "bucket": "REDACTED",
            "key": "d5654f8f-0cd0-45a2-a77f-3edda01feca0",
            "contentLength": 0
          },
          "hasChangedPassword": true,
          "id": 1
        },
        "id": 54
      },
      "quantity": 0,
      "id": 135
    },
    {
      "swag": {
        "Name": "Swag 3",
        "Description": "Mo' Swag",
        "Quantity": 1,
        "Owner": {
          "username": "robcowell",
          "password": "REDACTED",
          "email": "REDACTED",
          "fullname": "Rob Cowell",
          "isAdmin": true,
          "isActive": true,
          "Photo": {
            "bucket": "REDACTED",
            "key": "d5654f8f-0cd0-45a2-a77f-3edda01feca0",
            "contentLength": 0
          },
          "hasChangedPassword": true,
          "id": 1
        },
        "id": 55
      },
      "quantity": 0,
      "id": 136
    },
    {
      "swag": {
        "Name": "Test swag with an inordinately long name purely for the purposes of testing the rendering of these columns",
        "Description": "As above",
        "Quantity": 1,
        "Owner": {
          "username": "robcowell",
          "password": "REDACTED",
          "email": "REDACTED",
          "fullname": "Rob Cowell",
          "isAdmin": true,
          "isActive": true,
          "Photo": {
            "bucket": "REDACTED",
            "key": "d5654f8f-0cd0-45a2-a77f-3edda01feca0",
            "contentLength": 0
          },
          "hasChangedPassword": true,
          "id": 1
        },
        "id": 60
      },
      "quantity": 0,
      "id": 137
    }
  ],
  "offerTo": {
    "username": "todd",
    "password": "REDACTED",
    "email": "REDACTED",
    "fullname": "Todd Halfpenny",
    "isAdmin": false,
    "isActive": true,
    "hasChangedPassword": true,
    "id": 20
  },
  "offerFrom": {
    "username": "robcowell",
    "password": "REDACTED",
    "email": "REDACTED",
    "fullname": "Rob Cowell",
    "isAdmin": true,
    "isActive": true,
    "Photo": {
      "bucket": "REDACTED",
      "key": "d5654f8f-0cd0-45a2-a77f-3edda01feca0",
      "contentLength": 0
    },
    "hasChangedPassword": true,
    "id": 1
  },
  "targetSwag": {
    "Name": "Todd's tshirts",
    "Description": "Nice tshirts by Todd",
    "Quantity": 10,
    "Owner": {
      "username": "todd",
      "password": "REDACTED",
      "email": "REDACTED",
      "fullname": "Todd",
      "isAdmin": false,
      "isActive": true,
      "hasChangedPassword": true,
      "id": 20
    },
    "Photo": {
      "bucket": "REDACTED",
      "key": "f627cbcf-7eba-400d-a1f9-dcf1ab457709",
      "contentLength": 0
    },
    "id": 53
  },
  "id": 133
}
Rob Cowell
  • 1,610
  • 3
  • 18
  • 34
  • Tested the object JSON on the way *into* the form, and the Offerlines exist.. – Rob Cowell Dec 15 '18 at 20:55
  • 1
    I haven't tested, but my guess is that on the way back into the submitOffer, there is no `myoffer.id` to link back to the offerlines you are submitting. Maybe add a hidden field with the id of the offer. What do you see in the printlines? – Codemwnci Dec 15 '18 at 21:04
  • Yeah, passing myOffer.Id, but println gives before and after differences - `Offerlines passed to form - [149(Test Swag - 0), 150(Swag 2 - 0), 151(Swag 3 - 0), 152(Test swag with an inordinately long name purely for the purposes of testing the rendering of these columns - 0)] Download for swag 1 Swag photo utils.S3Blob@faec98 Requested 1 My offer coming out 148 Todd's tshirts Offerlines []` – Rob Cowell Dec 15 '18 at 21:36
  • So on the submitOffer method, the "parent" properties of myOffer appear to be set, but my offerLines collection is wiped out – Rob Cowell Dec 15 '18 at 21:43
  • 1
    If you check out https://www.playframework.com/documentation/1.5.x/controllers#binding, it suggests for POJO Arrays, it expects the http array notation. – Codemwnci Dec 15 '18 at 22:03

1 Answers1

1

Can you try the following to set the indexes to cope with arrays.

#{list items:myOffer.offerLines, as:'offerline'}

<tr>
<td height="32" width="30"><input type="text" id="offerline.id" name="offerline[${offerline_index-1}].id" value="${offerline.id}"/></td>
<td height="32" width="80">
    ${offerline.swag.Name}
</td>
<td height="32">
    <input class="field" id="offerline.quantity" name="offerline[${offerline_index-1}].quantity" type="number" min="0" max="${offerline.swag.Quantity}" value="${offerline.quantity}"/>
</td>
</tr> 
#{/list}
Codemwnci
  • 54,176
  • 10
  • 96
  • 129
  • Hasn't made a difference. I changed the names to `myOfffer.offerLines[${offerline_index-1}]` for further attempts at forcing a binding, and now I get `org.hibernate.PersistentObjectException: detached entity passed to persist: models.OfferLine` - calling it a night and sleeping on it now – Rob Cowell Dec 15 '18 at 22:19
  • 1
    I assume that that error message at least means you are now receiving the offerLines on the Offer object when you invoke the submitOffer action? I think you are now getting into the realms of JPA that is out of my depth (i've left JPA behind and started hand-rolling SQL for these exact reasons, both on Play2, and Kotlin web frameworks),. – Codemwnci Dec 16 '18 at 12:55
  • Fix seemed to be setting CascadeType to MERGE on the Offer side of the relationship, based on this answer - https://stackoverflow.com/a/29235227/139530 – Rob Cowell Dec 16 '18 at 21:23