Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding child elements onto a domain object before the domain object is created

(Sorry if this is a noob question, I couldn't find the answers on the grails reference)

I have the following domain heirarchy :

User > (has many) Survey > (has many) SurveyQuestion > (has many) SurveyQuestionResponse

These are two of the above :

class Survey {

    String surveyName

    static hasMany = [questions: SurveyQuestion]
    static belongsTo = [user:User]
    static constraints = {
    }
}

class SurveyQuestion {

    String question

    static hasMany = [responses : SurveyQuestionResponse]
    static belongsTo = [survey:Survey]

    static constraints = {
    }
}

When I create a Survey, I first see a screen like this :

(survey)

I fill in the survey name, then click add a survey question, and see the next screen :

(survey question)

But it requires a survey being set, which hasn't yet completed.

Question : Do I have to create and save the survey first, then edit it and add survey questions (each of which individually need to be created and saved before I can create responses), or is there a way to add child objects as I'm creating the parent objects?

I want to use dynamic scaffolding so I don't have to create controllers and views manually.

The questions and answers are entirely independent, and will not be re-used across the hierarchy.

like image 889
Jimmy Avatar asked Aug 30 '12 15:08

Jimmy


2 Answers

You should use command objects. This way you can comfortably add child elements while creating the parent. E.g.

class CreateSurveyCommand {
     String surveyName
     List<SurveyQuestion> surveyQuestions = 
         org.apache.commons.collections.list.LazyList.decorate(
             new ArrayList(), 
             new org.apache.commons.collections.functors.InstantiateFactory(SurveyQuestion.class))
}

In the view (assuming index.gsp) you have something like:

<g:textField name="surveyName" value="${cmd?.question}" />
<g:each in="${cmd.surveyQuestions}" var="surveyQuestion" status="i">
    <g:textField
        name="surveyQuestions[i].question" 
        value="${cmd?.surveyQuestions[i].question}" />
</g:each>
<g:actionSubmit action="addQuestion"/>

Having an addQuestion action within your controller:

def addAction(CreateSurveyCommand cmd) {
    cmd.surveyQuestions.add(new SurveyQuestion())
    render(view:"index", model: [cmd: cmd])
}

Editing is another topic, but works the same way.

Have a look at this blog post:

http://blog.andresteingress.com/2012/06/29/groovy-2-0-love-for-grails-command-objects

like image 181
Chris Avatar answered Sep 19 '22 14:09

Chris


Using that user interface you should create, save and add. A better approach is to create a master/detail user interface. You can see that approach here:

https://github.com/leadVisionary/Grails-Survey-Module

http://programmingitch.blogspot.com/2009/10/data-binding-for-one-to-many.html

http://omarello.com/2010/08/grails-one-to-many-dynamic-forms/

http://java.dzone.com/articles/creating-master-detail-forms

http://kapilpandit.wordpress.com/2009/02/25/complex_form_grails/

like image 26
AA. Avatar answered Sep 20 '22 14:09

AA.