Creating a view with Domain object fields - grails

I have the following domain classes.
Address
String number
String roadName
String country
Person
String fName
String age
Address address
I have a view called PersonViewSave i want the user to be able to save Person information from this view. When creating a Person record the user needs to create a Address record as well.
My Person controller looks like this:
PersonViewSave ={
def ad = new Address(number: '11', roadName: 'round road', country:'France').save()
new Person(fName: 'Alex', age: '23', address:ad).save()
}
1.) How do i collect parameters from the view and bring it to the PersonViewSave method ? (And can someone show me a sample GSP view file with the Person and Address textfields)
2.) Incase if there's an error in the Address created, how do i prevent creating a Person object with an address as shown in this line new Person(fName: 'Alex', age: '23', address:ad).save()
UPDATE
<g:form name="myForm" method="post" action="doIt">
<p>Person info:</p>
<label for="firstName">First Name</label>
<g:textField name="firstName" id="firstName" />
<p>Address Info:</p>
<label for="roadName">Street Number</label>
<g:textField name="roadName" id="roadName" />
<g:submitButton name="submit" value="Submit" />
Here, i have only used few objects from the Domain classes just to see if it works.
I also have a parameter called createdDate in both Domain classes. That as well needs to be auto inserted.
My Service Class is as follows:
def saveService () {
def ad = new Address(params)
if (ad.save(flush: true)) {
def p = new Person(params)
p.address = ad
p.save()
} else {
// display validation errors
}
}
1.) I get an error and it is > No such property: params for class: pro.PersonService
2.) What hapence i have 2 domain class with parameters that has the same Name. For example Animal and Person domain classes have an parameter called firstName. According to your previous solution how will grail distinguish to what domain class it belongs to ?
I am using Grails 2.2.4

Here is a way to check that the Address saved correctly:
def ad = new Address(params)
if (ad.save(flush: true)) {
def p = new Person(params)
p.address = ad
p.save()
} else {
// display validation errors
}
This returns the Address if it saved properly, which results in true, otherwise it returns null (or false).
Also, you can use data binding via the params map to create your objects from parameters. As long as the key in params matches up to a property name in your Address and Person class, the value of the parameter will be assigned to the object.
So, for instance, to map your Person, you will need fields like the following:
<g:form name="personForm" method="post" action="PersonViewSave">
<p>Person info:</p>
<label for="fName">First Name</label>
<g:textField name="fName" id="fName" />
<label for="age">Age</label>
<g:textField name="age" id="age" />
<p>Address Info:</p>
<label for="number">Street Number</label>
<g:textField name="number" id="number" />
<label for="roadName">Road</label>
<g:textField name="roadName" id="roadName" />
<label for="country">Country</label>
<g:textField name="country" id="country" />
<g:submitButton name="submit" value="Submit" />
</g:form>

you can try this
def ad = new Address(number:params.number , roadName:params.roadName , country: params.country)
if (ad.save(flush: true)) {
def p = new Person(fName:params.fName , age: params.age, address:ad)
p.save()
} else {
// display validation errors
}

Related

Problems with form gsp

I'm trying to send parameters from my form (gsp) to my controller grails, but doesn't work.
<g:form url="[action:'searchByFilter', controller:'invoice']" method="GET">
<p>Filtro de busca</p>
<g:textField name="search" value="${invoice?.search}" params="search : search"/>
<g:submitButton name="search" class="input-search" value="${message(code: 'default.button.search.filter')}" />
</g:form>
I need to send input's value to do a result's filter. But, input's value isn't sending.
My domain class code:
static namedQueries = {
getInvoicesByStatus {
eq 'deleted', false
}
getInvoicesByFilter {
eq 'description', Invoice.get(params.search)
}
}
What's my mistake? I need to use namedQuery :)

How to prevent data input for being erase in Grails with reCaptcha

I have gsp with two textfield for firstname-lastname and reCaptcha. What I want is for every wrong captcha code the user's input for firstname and last name won't be erased.
snippet for controller:
***captcha_code****
if (result) {
def person = new Person(params)
person.save()
render "Success!"
} else {
flash.message = message(code: 'forgotPassword.captcha.wrong')
redirect(controller:'person', action:'form')
}
snipper for form.gsp
***captcha_code_here***
<g:form controller="person" action="save">
<label>First Name: </label>
<g:textField name="firstName"/><br/>
<label>Last Name: </label>
<g:textField name="lastName"/><br/>
<g:if test="${flash.message}">
<div class="message" role="status" style="font-size: medium;color: green;">${flash.message}</div>
</g:if>
***captcha_code_here***
<g:actionSubmit value="Save"/>
To repopulate the fields you can use the same flash scope you're using for the message. On error, add the first and last name to the flash scope, and then in your GSP use those values when they are available:
PersonController
class PersonController {
def save() {
...
if(/* recaptcha failed */) {
flash.firstName = params.firstName
flash.lastName = params.lastName
}
...
}
}
GSP
<label>First Name: </label>
<g:textField name="firstName" value="${flash.firstName ?: ''}"/><br/>
<label>Last Name: </label>
<g:textField name="lastName" value="${flash.lastName ?: ''}"/><br/>
In Controller Action, send back fields that you want to be repopulated.

Getting a value from g:select in Grails

I'm trying to create my own 'edit' form in my grails application.
My g:select is currently populated with stuff from my database and looks like this:
<g:select name="nameList" from="${Card.list()}" value="${name} " />
And then the value :
<g:field name="amount" type="number" value="" required=""/>
My domain has only two variables - name and amount. I want to select the item from the dropdown box, type in the amount and just click 'update', my update method is a default one generated by grails so it requires ID and Version, how would I go about passing it through?
My update button ;
<g:actionSubmit class="save" action="update" value="${message(code: 'default.button.update.label', default: 'Update')}" />
My domain code:
package cardstorage
class Card {
String name;
int amount;
static constraints = {
name(blank:false);
amount(blank:false);
}
String toString(){
return name;
}
}
Thank you
I have fixed it but I'm sure it is not a proper way to do so.
<g:form method="post" >
<g:select name="card" from="${Card.list()}" optionValue ="name" optionKey="id" />
<g:field name="amount" type="number" value="" required=""/>
<fieldset class="buttons">
<g:actionSubmit class="save" action="update" value="${message(code: 'default.button.update.label', default: 'Update')}" />
</fieldset>
</g:form>
thats my code for the g:select. In my Controller method, passing the value of 'card' to the 'Long id' would result in 'id' being 49 (null + 1 = 49?)
def update(Long id, Long version) {
id = params.card;
id = id- 48;
...
}
Now I'm able to update my records, however I'm curious how should I have done this more properly.

Grails databinding multiple domain classes

HI. I have this classes:
class Carro {
String name
String marca
String matricula
static constraints = {
name(nullable:false, blank:false)
}
static mapping = {
version false
}
}
class CarroMovel {
String move
String rodas
String espelhos
Carro carro
static hasMany = [carros: Carro]
static constraints = {
move(nullable:false, blank:false)
}
static mapping = {
version false
}
}
And the controllers:
class CarroController{
def save2 = {
def carroInstance = new Carro()
carroInstance.name = params.name
carroInstance.marca = params.marca
carroInstance.matricula = params.matricula
if (carroInstance.save(flush: true)) {
redirect(uri:"/home.gsp")
}
else {
render(view: "/testeAdd", model: [carroInstance: carroInstance])
}
}
And the view testeAdd.gsp
<g:form controller="carro" action="save2">
<h1>Add New Carro Record</h1>
<p>Basic Information</p>
<label>Name
<span class="small">as</span>
</label>
<input type="text" name="name" value="${carroInstance?.name}" /><br>
<label>Marca
<span class="small">as</span>
</label>
<input type="text" name="marca" value="${carroInstance?.marca}" /><br
<label>Matricula
<span class="small">as</span>
</label>
<input type="text" name="matricula" value="${carroInstance?.matricula}" /><br>
<g:submitButton name="save" value="Save" id="oneone"/>
<div class="spacer"></div>
</g:form>
<g:hasErrors bean="${carroInstance}">
<div class="errors">
<g:renderErrors bean="${carroInstance}" as="list" />
</div>
</g:hasErrors>
This is working good. Now i would like to be able to data binding multiple domain classes. So, along with the current code from my gsp file, i would also like to add carroMovel occurrences all in same save2. Im not sure how to do that, specially cause class Carro will need to have an id from class carroMovel. Any help please? Thank you.
I folowed some suggestions and now the results are as follows (im not concerned about error validation yet):
def save3 = {
def carroInstance = new Carro()
def carroMovelInstance = new CarroMovel()
carroInstance.name = params.carro.name
carroInstance.marca = params.carro.marca
carroInstance.matricula = params.carro.matricula
carroMovelInstance.move = params.carroMovel.move
carroMovelInstance.rodas = params.carroMovel.rodas
carroMovelInstance.espelhos = params.carroMovel.espelhos
carroInstance.save()
carroMovelInstance.carro = carroInstance
carroMovelInstance.save()
}
<g:form controller="carro" action="save3">
<h1>Add New Conference Record</h1>
<p>Basic Information</p>
<label>Name
<span class="small">Add your name</span>
</label>
<input type="text" name="carro.name" value="${carroInstance?.name}" /><br>
<label>Marca
<span class="small">Add your name</span>
</label>
<input type="text" name="carro.marca" value="${carroInstance?.marca}" /><br
<label>Matricula
<span class="small">Add your name</span>
</label>
<input type="text" name="carro.matricula" value="${carroInstance?.matricula}" /><br>
<label>Move
<span class="small">Add your name</span>
</label>
<input type="text" name="carroMovel.move" value="${carroMovelInstance?.move}" /><br>
<label>Rodas
<span class="small">Add your name</span>
</label>
<input type="text" name="carroMovel.rodas" value="${carroMovelInstance?.rodas}" /><br>
<label>Espelho
<span class="small">Add your name</span>
</label>
<input type="text" name="carroMovel.espelho" value="${carroMovelInstance?.espelho}" /><br>
<g:submitButton name="save" value="Save" id="addConference"/>
The Carro object is saved in the database, altought, nothing happens with CarroMovel and it is not saved and i can't figure it out.
First I would change the input names to carro.name, carro.marca, carroMovel.move, ... so that they are differentiated by name.
<input type="text" name="carro.name"/><br>
<input type="text" name="carro.marca"/><br>
<input type="text" name="carroMovel.move"/><br>
This has the advantage that the binding in the controller can be done the standard Grails way, and that the correct values are entered in the form without the value attribute set.
carro.properties = params.carro
carroMovel.properties = params.carroMovel
In the controller action you can also save and link the Carro and CarroMovel instances.
carro.save()
carroMovel.carro = carro
carroMovel.save()
if(carroMovel.hasErrors(){
render(view: 'save3', model: [carro: carro, carroMovel.carroMovel])
}
If I understand your question correctly, you can give this a try.
First, edit our form to include the necessary fields for the CarroMovel class,
e.g
<label>Move
<span class="small">as</span>
</label>
<input type="text" name="move" value="${carroMovelInstance?.move}" />
then
in your save2 action,
def carroInstance = new Carro()
carroInstance.name = params.name
carroInstance.marca = params.marca
carroInstance.matricula = params.matricula
def carroMovelInstance = new CarroMovel()
carroMovelInstance.name = params.move
carroMovelInstance.marca = params.rodasa
carroMovelInstance.matricula = params.espelhos
carroMovelInstance.carro = carroInstance
Since Carro does not belong to CarroMovel saving a carroMovelInstance will not cascade to the carroInstance, therefore you will need to save each instance individually before saving its owning instance.
carroMovelInstance.carro.save()
if (carroMovelInstance.save(flush: true)) {
redirect(uri:"/home.gsp")
}
else {
render(view: "/testeAdd", model: [carroInstance: carroInstance, carroMovelInstance:carroMovelInstance])
}
Let me know if that works out for you.
Some of the other answers may be simpler, but I've been using this technique:
http://omarello.com/2010/08/grails-one-to-many-dynamic-forms/
In order for Carro to cascade save the CarroMovel reference, CarroMovel needs belongsTo = Carro or you need to manually tell hibernate to cascade it upon save using something like this:
class CarroMovel{
static mapping = {
carro cascade: 'all'
}
}
Here's the hibernate documentation about cascading:
https://docs.jboss.org/hibernate/orm/4.0/javadocs/org/hibernate/metamodel/binding/CascadeType.html
I usually use a command object for this type of thing.
In your controller do something like this:
class CarroController {
def show = {
[cmd: new MyCommand()]
}
def save2 = { MyCommand cmd ->
def carro = cmd.carro
if (carro.save()) {
cmd.movel.carro = carro
if (cmd.movel.save()) {
redirect uri: 'home.gsp'
} else {
// show form again
render view: 'show', model:[cmd:cmd]
}
} else {
// show form again
render view: 'show', model:[cmd:cmd]
}
}
// same file or some other class file
class MyCommand {
Carro carro
CarroMovel movel
}
}
You will need to adjust your form a bit as well...
Where you have "Carro" fields reference them like this:
<input type="text" name="carro.matricula" value="${cmd.carro?.matricula}" />
Where you have the "CarroMovel" fields, like this:
<input type="text" name="movel.rodas" value="${cmd.movel?.rodas}" />
This code might not be exactly right (I didn't test it), but should get you down the correct path. Also instead of referencing the objects in the command object, you could just have the fields that you are binding, and then build the actual domain objects from them, either through a helper method (def buildCarro(){...}) or by hand in the controller method.

Grails controllers

I have a form similar to this one in Grails:
Name: _____
Age: _____
Street: _____
Email: ____
|Submit|
How can i pass all the filled in information to a controller that will add me the records to the database? Im kinda new to Grails, and my problem is i dont understand how to "pass" and get things to the controllers.
class Person {
String name
Integer age
String street
String email
}
class PersonController {
def save = {
def personInstance = new Person(params)
personInstance.save(flush:true)
}
}
<g:form controller="person" action="save">
<g:textField name="name" />
<g:textField name="age" />
<g:textField name="street" />
<g:textField name="email" />
<g:submitButton name="save" value="Save" />
</g:form>
Also, if you have a domain, you can run
grails generate-all com.foo.Person
And all the code will be generated for you. Then you can see how it is done.

Resources