Grails Parent Child Form not saving child data -
i trying create parent child form author , book domain classes. view works fine , lets me enter books when creating new author. however, when add new author , books , check database (dbconsole), see new record in author table no records added book table. can please let me know missing or doing wrong here?
here domain classes:
author:
package bookauthor1tomany import org.apache.common.collections.list.* import org.apache.commons.collections.listutils.* class author { static constraints = { } string name string category list<book> books = new arraylist<>() static hasmany = [ books:book ] static mapping = { books cascade:"all-delete-orphan" } def getexpandablebooklist() { return lazylist.decorate(books, factoryutils.instantiatefactory(book.class)) } string tostring(){ return "${name}" - "${category}" } } book
package bookauthor1tomany class book { static constraints = { } string title boolean _deleted static transients = [ '_deleted' ] static belongsto = [ author:author ] def string tostring() { return title } } authorcontroller
i haven't changed controller. default generated save method author controller.
@transactional def save(author authorinstance) { if (authorinstance == null) { notfound() return } if (authorinstance.haserrors()) { respond authorinstance.errors, view:'create' return } authorinstance.save flush:true request.withformat { form multipartform { flash.message = message(code: 'default.created.message', args: [message(code: 'author.label', default: 'author'), authorinstance.id]) redirect authorinstance } '*' { respond authorinstance, [status: created] } } } gsps
create.gsp
<!doctype html> <html> <head> <meta name="layout" content="main"> <g:set var="entityname" value="${message(code: 'author.label', default: 'author')}" /> <title><g:message code="default.create.label" args="[entityname]" /></title> </head> <body> <a href="#create-author" class="skip" tabindex="-1"><g:message code="default.link.skip.label" default="skip content…"/></a> <div class="nav" role="navigation"> <ul> <li><a class="home" href="${createlink(uri: '/')}"><g:message code="default.home.label"/></a></li> <li><g:link class="list" action="index"><g:message code="default.list.label" args="[entityname]" /></g:link></li> </ul> </div> <div id="create-author" class="content scaffold-create" role="main"> <h1><g:message code="default.create.label" args="[entityname]" /></h1> <g:if test="${flash.message}"> <div class="message" role="status">${flash.message}</div> </g:if> <g:haserrors bean="${authorinstance}"> <ul class="errors" role="alert"> <g:eacherror bean="${authorinstance}" var="error"> <li <g:if test="${error in org.springframework.validation.fielderror}">data-field-id="${error.field}"</g:if>><g:message error="${error}"/></li> </g:eacherror> </ul> </g:haserrors> <g:form url="[resource:authorinstance, action:'save']" > <fieldset class="form"> <g:render template="authortemp"/> </fieldset> <fieldset class="buttons"> <g:submitbutton name="create" class="save" value="${message(code: 'default.button.create.label', default: 'create')}" /> </fieldset> </g:form> </div> </body> </html> _form.gsp
<%@ page import="bookauthor1tomany" %> <div class="fieldcontain ${haserrors(bean: authorinstance, field: 'books', 'error')} "> <label for="books"> <g:message code="author.books.label" default="books" /> </label> <ul class="one-to-many"> <g:each in="${authorinstance?.books?}" var="b"> <li><g:link controller="book" action="show" id="${b.id}">${b?.encodeashtml()}</g:link></li> </g:each> <li class="add"> <g:link controller="book" action="create" params="['author.id': authorinstance?.id]">${message(code: 'default.add.label', args: [message(code: 'book.label', default: 'book')])}</g:link> </li> </ul> </div> <div class="fieldcontain ${haserrors(bean: authorinstance, field: 'name', 'error')} required"> <label for="name"> <g:message code="author.name.label" default="name" /> <span class="required-indicator">*</span> </label> <g:textfield name="name" required="" value="${authorinstance?.name}"/> </div> _authortemp.gsp
<div class="dialog"> <table> <tbody> <tr class="prop"> <td valign="top" class="name"><label for="name">name:</label></td> <td valign="top" class="value ${haserrors(bean:authorinstance,field:'name','errors')}"> <input type="text" id="name" name="name" value="${fieldvalue(bean:authorinstance,field:'name')}"/> </td> </tr> <tr class="prop"> <td valign="top" class="name"><label for="category">category:</label></td> <td valign="top" class="value ${haserrors(bean:authorinstance,field:'category','errors')}"> <input type="text" id="category" name="category" value="${fieldvalue(bean:authorinstance,field:'category')}"/> </td> </tr> <tr class="prop"> <td valign="top" class="name"><label for="books">books:</label></td> <td valign="top" class="value ${haserrors(bean:authorinstance,field:'books','errors')}"> <g:render template="books" model="['authorinstance':authorinstance]" /> </td> </tr> </tbody> </table> </div> _books.gsp
<script type="text/javascript"> var childcount = ${authorinstance?.books.size()} + 0; function addchild() { var htmlid = "book" + childcount; var deleteicon = "${resource(dir:'images/skin', file:'database_delete.png')}"; var templatehtml = "<div id='" + htmlid + "' name='" + htmlid + "'>\n"; templatehtml += "<input type='text' id='expandablebooklist[" + childcount + "].title' name='expandablebooklist[" + childcount + "].title' />\n"; templatehtml += "<span onclick='$(\"#" + htmlid + "\").remove();'><img src='" + deleteicon + "' /></span>\n"; templatehtml += "</div>\n"; $("#childlist").append(templatehtml); childcount++; } </script> <div id="childlist"> <g:each var="book" in="${authorinstance.books}" status="i"> <g:render template='book' model="['book':book,'i':i]"/> </g:each> </div> <input type="button" value="add book" onclick="addchild();" /> _book.gsp
<div id="book${i}"> <g:hiddenfield name='expandablebooklist[${i}].id' value='${book.id}'/> <g:textfield name='expandablebooklist[${i}].title' value='${book.title}'/> <input type="hidden" name='expandablebooklist[${i}]._deleted' id='expandablebooklist[${i}]._deleted' value='false'/> <span onclick="$('#expandablebooklist\\[${i}\\]\\._deleted').val('true'); $('#expandablebooklist${i}').hide()">delete</span> </div>
you don't need
list<book> books = new arraylist<>() in domain. hasmany give books collection default. might causing issues. also, have debugged in controller make sure books collection populated when save occurs.
Comments
Post a Comment