Grails one-to-many databinding with dynamic forms

2019-09-14 04:44发布

问题:

I'm using Grails 2.3.5 and try to persist multiple domains coming from a dynamic form.

To achieve this, I used the approach with lazy lists like described in: http://omarello.com/2010/08/grails-one-to-many-dynamic-forms/

The forms are genereated well and all the neccessary parameters are in the params-map, but the binding to the list does not work.

I read a lot about this topic the last two days and found good answers on stackoverflow, but I think these methods only work for older grails versions.

To illustrate my problem, some code:

House.groovy

class House {

....attributes removed to minimize example


List<Adress> adresses = [].withLazyDefault { new Adress() }
// List adresses = ListUtils.lazyList(new ArrayList<Adress>,FactoryUtils.instantiateFactory(Adress.class)); 
static hasMany = [adresses:Adress]


      //def getAdresses(){
      //return LazyList.decorate(adresses, FactoryUtils.instantiateFactory(Adress.class))
      //}   

static mapping = {
    adresses cascade:"all-delete-orphan"
}

Template for dynamic forms --> Are created correctly

<div id="adress${i}" class="adresses-div" style="<g:if test="${hidden}">display:none;</g:if>margin-bottom:10px; ">
<g:hiddenField name='adresses[${i}].id' value='${adresses?.id}'/>
<g:hiddenField name='adresses[${i}].deleted' value='false'/>
<g:hiddenField name='adresses[${i}].neu' value="${adresses?.id == null?'true':'false'}"/>

<g:textField name='adresses[${i}].street' value='${adresses?.street}' />
<g:textField name='adresses[${i}].land' value='${adresses?.land}' />    

<span class="del-adresses">
    <img src="${resource(dir:'images/skin', file:'database_delete.png')}" 
        style="vertical-align:middle;"/>
</span>

HouseController - edit action

houseInstance.properties = params

So, the form templates are created correctly and the the input values are existent in the parameter map.

My problem is now the databinding for multiple adresses created from one form. According to the example project provided by the link above, the parameter binding should automatically create new Adress-Objects and save them as childs for a house.

When debugging my application I can see that there are the right parameters but it seems that the list cannot create a new Adress-Object.

The 'adresses' list, contains a null value after binding--> [null]

Like mentioned above, I tried a few solutions for this problem, but couldn't resolve it. Probably the lazylist approach is not supported in grails 2.3.5 and only works for older version.

I hope someone had the same same problem and can give me a hint

Thanks in advance

回答1:

I have experience with the same problem. Refer to this: grails 2.3 one-to-many databinding with dynamic forms

Try to remove id: in params if it's a new phone. Tested with grails 2.3.11 and using it in my project.

Here is what I changed in _phone.gsp

<div id="phone${i}" class="phone-div" <g:if test="${hidden}">style="display:none;"</g:if>>
     <g:if test="${phone?.id != null}">
           <g:hiddenField name='phones[${i}].id' value='${phone?.id}'/>
     </g:if>
     ...
</div>

Thanks to @hakuna1811



回答2:

After carefully reading the docs for grails 2.3.x, I saw how the parameter map should look like with multiple child-domains.

Example:

def bindingMap = [name: 'Skyscraper', 
              'addresses[0]': [street: 'FirstStreet'], 
              'addresses[1]': [street: 'SecondStreet']]

But my map looked like this:

def bindingMap = [name: 'Skyscraper', 
              'addresses[0]': [street: 'FirstStreet', 'SecondStreet']]

I have never noticed this before...

The problem was the jQuery code to clone all the necessary input fields and update the corresponding ids. By removing this code and testing my application with two static address fields I got it to work.

<g:textField name="adresses[0].street" value=""/>
<g:textField name="adresses[0].zip" value=""/>


<g:textField name="adresses[1].street" value=""/>
<g:textField name="adresses[1].zip" value=""/>

As a short-term solution I decided to create predefined hidden forms. When clicking on the add-Button some simple jQuery will show one form...

The next couple of days I will review my code to get really dynamic behaviour. If I have results, I will add them to the topic here.