The bean class looks like this:
String houseNo
String address
Person person
The view looks like this
<g:form action="save">
<fieldset class="form">
<g:render template="form" />
</fieldset>
<fieldset class="buttons">
<g:submitButton name="create" class="save"
value="${message(code: 'default.button.create.label', default: 'Create')}" />
</fieldset>
</g:form>
According to my knowledge in Grails, i think is <g:render template="form" /> will pull all form attributes and display it.
But what i want to do is Instead of displaying a drop-down for Person, i want to display all Person related fields like personName, personAge. How can i display these fields in a label underneath ?
Help
You're correct about the way g:render works, the template part refers to a GSP which will look through the bean values and print them according to the html + groovy markup in "_form.gsp" (located in your views folder under the controller name).
To change the way the Person domain object is displayed, simply edit this "_form.gsp" and take out the 'select' html code - replacing it with groovy markup using the property values of the bean, eg.
${beanName.person.personName} //(use the existing code to help workout the bean name etc)
Hopefully that helps you on your way.
Related
Recently I began to study Grails, and I noticed that the file create.groovy is generated by a dynamic scaffold. The form tag doesn't have an attribute called controller, only action.
So my question is, how does the Grails framework discover the controller that should be called?
<g:form action="save">
<fieldset class="form">
<f:field bean="categoria" property="nome" class="form-control" />
</fieldset>
<fieldset class="buttons">
<g:submitButton name="create" class="save" value="${message(code: 'default.button.create.label', default: 'Create')}" />
</fieldset>
</g:form>
Thanks, and sorry for my bad english!
Grails uses "convention over configuration" so whenever you use a form without controller, grails will use the default convention.
Since your view is put in a folder named after a controller, grails will assume that the default controller for any view inside that folder is the one that matches with the folder name. Example
BookController is the default controller for any gsp inside the grails-app/views/book folder.
*This convention also applies to things like links.
I am having a problem saving a domain instance in grails; The domainInstance that's passed to the default update method in my controller is NULL. The GSP page I am submitting from is not the default edit page. I have certain values from DB that need to be saved. I have the form tag defined on the page that contains the values I need to submit, as follows.
<g:form id="sampleForm" url="[resource:domainInstance, controller:'cntrlrName', action:'update']" method="PUT" >
I also have a version field which looks like this.
<g:hiddenField name="version" value="${domainInstance?.version}" />
My g:submit is as follows
<g:actionSubmit action="update" value="${message(code: 'default.button.update.label', default: 'Update')}" />
Why is my domain instance null? What am I missing?
This is the common mistake one could make. The attribute id in <g:form> tag is not the id attribute of HTML tags but it is the id to use in the link for default mapping of Grails i.e.
"/$controller/$action/$id" {}
So change your tag as:
<g:form name="sampleForm" id="${domainInstance.id}" controller="cntrlrName" action="update" method="PUT">
You can pass the domainInstance but I feel it is better practice to pass the id instead of the object. Try passing the id of the domain instance and then reading the object in the controller.
<g:form name="sampleForm" action="action" controller="controller" id="${domainInstance.id}" ></g:form>
// in controller
def resource = Domain.read(params.id)
another approach could be to pass the domainInstance as a hiddenField
<g:hiddenField name="resource" value="$domainInstance" />
Using model binding with the above like so:
<asp:FormView runat="server" ID="ConversationForm" DefaultMode="Edit"
OnCallingDataMethods="ConversationForm_CallingDataMethods"
ItemType="MyApp.Model.Conversation"
DataKeyNames="ConversationID"
SelectMethod="GetConversation"
UpdateMethod="UpdateConversation"
OnItemUpdated="Conversation_ItemUpdated">
<EditItemTemplate>
<fieldset>
<legend>Conversation Notes:</legend>
<ol>
<asp:DynamicEntity runat="server" Mode="Edit" />
</ol>
</fieldset>
<asp:Button ID="btnUpdate" runat="server" Text="Save" CommandName="Update" />
<asp:Button ID="btnCancel" runat="server" Text="Cancel" CausesValidation="false" OnClick="btnCancel_Click" />
</EditItemTemplate>
</asp:FormView>
The Conversation entity basically has one property, "Text", which should contain freeform text captured by the user.
The DynamicEntity control generates a simple textbox for this property as it has a datatype of string.
How do I tell it to create a multiline textbox instead?
Can I add some sort of data annotation to the Conversation class that will tell the Dynamic Templates to create a multiline textbox?
It does not seem to be possible so I had to revert to using a static asp:Textbox control with the TextMode="MultiLine" property set.
I'm starting with Grails and I don't know how should I face the following use case.
The app is about sports results prediction, so I have in my domain "Match" and "Prediction", and I want to have one view where the user can update all the predictions of matches that haven't been played yet.
So far I've defined a method in my "PredictionController" that searches all the already existing predictions of games that have to be played and generates new Prediction instances for any new Match with a date higher than now. I've created a view for that method and I'm getting correctly all the predictions that I should complete or update, and I've defined in my controller another method for the form sumbission (so I'm trying to resolve this in the same way that the 'create' and 'update' scaffolded methods work).
My question is, How can I access to all the Predictions modified by my view? How can I send all the predictions to my update method? Is it defining a hidden field with a variable containing all the collection?
This is the form in my GSP view:
<g:form action="savePredicctions">
<fieldset>
<g:each in="${predictions}">
<li>
<div>
${it.match.homeTeam}
<g:field name="${it.match}.homeGoals" type="number" value="${it.homeGoals}" />
</div>
-
<div>
<g:field name="${it.match}.awayGoals" type="number" value="${it.awayGoals}" />
${it.match.awayTeam}
</div>
</li>
</g:each>
</fieldset>
<fieldset class="submit">
<g:submitButton />
</fieldset>
</g:form>
You can use a command object to store the instances of Prediction.
#Validateable
class PredictionCommand {
//data binding needs a non-null attribute, so we use ListUtils.lazyList
List<Prediction> predictions = ListUtils.lazyList([], FactoryUtils.instantiateFactory(Prediction))
}
In your view, you need to control the index of your list, and send the attributes of Prediction to the controller:
<g:each in="${predictions}" status="i">
<g:textField name="predictions[$i].homeGoals" />
<g:textField name="predictions[$i].awayGoals" />
</g:each>
And in your controller you can use bindData() to bind params to your command:
class CommandController {
def save() {
PredictionCommand command = new PredictionCommand()
bindData(command, params)
println command.predictions
}
}
Say I have a Domain object Teacher with two fields String name, TeacherType teacherType, where TeacherType is an enum containing AssitantProfessor, AssociateProfessor, Professor.
After I generate the views using grails run-target generate-all Teacher, it produces an _form.gsp that is used for both create and edit of Teacher. In the edit view I want only the name to be editable but the TeacherType to be unmodifiable once created (this is just an example, it is a requirement that certain fields can't be updated after creation). In the create view, both TeacherType and name should be editable.
Since both create.gsp and edit.gsp render the _form template, what is the preferred approach here?
Create two separate templates i.e. _formCreate.gsp , _formEdit.gsp; Or
Pass in a model map within create.gsp and edit.gsp and use them in _form.gsp to conditionally render the view?
e.g.
In create.gsp:
<fieldset class="form">
<g:render template="form" model="[teacherInstance: teacherInstance, 'mode':'create']"/>
</fieldset>
In edit.gsp
<fieldset class="form">
<g:render template="form" model="[teacherInstance: teacherInstance, 'mode':'edit']"/>
</fieldset>
In _form.gsp
<g:if test="${mode == 'edit'}">
<g:select name="teacherType" from="${TeacherType?.values()}" keys="${TeacherType.values()*.name()}" required="" value="${teacherInstance?.teacherType?.name()}" disabled="disabled"/>
</g:if>
<g:else>
<g:select name="teacherType" from="${TeacherType?.values()}" keys="${TeacherType.values()*.name()}" required="" value="${teacherInstance?.teacherType?.name()}" disabled="false"/>
</g:else>
Approach 2 works but I suppose if the number of conditional statements increase it may just be better to follow approach 1 and split the forms.
Is there another approach that I'm not aware of?
The disabled attribute of <g:select> (and many other <g:...> form field tags) can be a boolean-valued expression:
<g:select name="teacherType" from="${TeacherType?.values()}"
keys="${TeacherType.values()*.name()}" required=""
value="${teacherInstance?.teacherType?.name()}"
disabled="${mode == 'edit'}"/>
This will render as disabled="disabled" if the expression evaluates to true, and as the absence of a disabled attribute (i.e. the field will not be disabled) if the expression is false. You could even use a boolean entry in the model, e.g. render the template with
model="[teacherInstance: teacherInstance, editing:true]"
(or editing:false respectively) and then say disabled="${editing}" on the <g:select>.