dataTable Can't show more than 10 rows in table - grails

I've encountered a problem while trying to list the users in the table using dataTable.
So far everything is working fine but when I enter more than 10 users, it still shows me 10 rows and can't view more than 10 rows. I've been trying to use the show by 10 25 50 100 entries but still can't work.
Here is the screen shot of the function that i've been trying to use:
This is the table that i use:
$(document).ready(function() {
$('table.dataTable').dataTable();
} );
This is my domain:
class Pilot {
String fName
String lName
static constraints = {
}
}
Here is the Controller:
class PilotController {
static allowedMethods = [save: "POST", update: "POST", delete: "POST"]
def index() {
redirect(action: "list", params: params)
}
def list(Integer max) {
params.max = Math.min(max ?: 10, 100)
[pilotInstanceList: Pilot.list(params), pilotInstanceTotal: Pilot.count()]
}
def create() {
[pilotInstance: new Pilot(params)]
}
def save() {
def pilotInstance = new Pilot(params)
if (!pilotInstance.save(flush: true)) {
render(view: "create", model: [pilotInstance: pilotInstance])
return
}
flash.message = message(code: 'default.created.message', args: [message(code: 'pilot.label', default: 'Pilot'), pilotInstance.id])
redirect(action: "show", id: pilotInstance.id)
}
def show(Long id) {
def pilotInstance = Pilot.get(id)
if (!pilotInstance) {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'pilot.label', default: 'Pilot'), id])
redirect(action: "list")
return
}
[pilotInstance: pilotInstance]
}
def edit(Long id) {
def pilotInstance = Pilot.get(id)
if (!pilotInstance) {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'pilot.label', default: 'Pilot'), id])
redirect(action: "list")
return
}
[pilotInstance: pilotInstance]
}
def update(Long id, Long version) {
def pilotInstance = Pilot.get(id)
if (!pilotInstance) {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'pilot.label', default: 'Pilot'), id])
redirect(action: "list")
return
}
if (version != null) {
if (pilotInstance.version > version) {
pilotInstance.errors.rejectValue("version", "default.optimistic.locking.failure",
[message(code: 'pilot.label', default: 'Pilot')] as Object[],
"Another user has updated this Pilot while you were editing")
render(view: "edit", model: [pilotInstance: pilotInstance])
return
}
}
pilotInstance.properties = params
if (!pilotInstance.save(flush: true)) {
render(view: "edit", model: [pilotInstance: pilotInstance])
return
}
flash.message = message(code: 'default.updated.message', args: [message(code: 'pilot.label', default: 'Pilot'), pilotInstance.id])
redirect(action: "show", id: pilotInstance.id)
}
def delete(Long id) {
def pilotInstance = Pilot.get(id)
if (!pilotInstance) {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'pilot.label', default: 'Pilot'), id])
redirect(action: "list")
return
}
try {
pilotInstance.delete(flush: true)
flash.message = message(code: 'default.deleted.message', args: [message(code: 'pilot.label', default: 'Pilot'), id])
redirect(action: "list")
}
catch (DataIntegrityViolationException e) {
flash.message = message(code: 'default.not.deleted.message', args: [message(code: 'pilot.label', default: 'Pilot'), id])
redirect(action: "show", id: id)
}
}
}
And here is the list View:
<!DOCTYPE html>
<html>
<head>
<meta name="layout" content="bstheme">
<g:set var="entityName" value="${message(code: 'pilot.label', default: 'Pilot')}" />
<title><g:message code="default.list.label" args="[entityName]" /></title>
</head>
<body>
<div class="col-md-12">
<div class="panel panel-custom">
<!--<g:message code="default.link.skip.label" default="Skip to content…"/>-->
<div class="panel-heading">
<g:message code="default.list.label" args="[entityName]" />
<div class="panel-options">
<a class="home" href="${createLink(uri: '/')}"><i class="glyphicon glyphicon-home"></i></a>
<g:link class="create" action="create"><i class="glyphicon glyphicon-plus"></i></g:link>
</div>
</div>
<div class="panel-body">
<div id="list-pilot" class="content scaffold-list" role="main">
<!--<h1><g:message code="default.list.label" args="[entityName]" /></h1>-->
<g:if test="${flash.message}">
<div class="message" role="status">${flash.message}</div>
</g:if>
<table class="dataTable table table-striped table-hover table-responsive">
<thead>
<tr>
<g:sortableColumn property="fName" title="${message(code: 'pilot.fName.label', default: 'First Name')}" />
<g:sortableColumn property="lName" title="${message(code: 'pilot.lName.label', default: 'Last Name')}" />
</tr>
</thead>
<tbody>
<g:each in="${pilotInstanceList}" status="i" var="pilotInstance">
<tr class="${(i % 2) == 0 ? 'even' : 'odd'}">
<td><g:link action="show" id="${pilotInstance.id}">${fieldValue(bean: pilotInstance, field: "fName")}</g:link></td>
<td>${fieldValue(bean: pilotInstance, field: "lName")}</td>
</tr>
</g:each>
</tbody>
</table>
<%-- <div class="pagination">
<g:paginate total="${pilotInstanceTotal}" />
</div> --%>
</div>
</div>
</div>
</div>
</body>
</html>

Found the solution to this problem,
def list(Integer max) {
params.max = Math.min(max ?: 10, 100)
[pilotInstanceList: Pilot.list(params), pilotInstanceTotal: Pilot.count()]
}
All you need to do is remove:
Math.min(max ?: 10, 100) in the controller,
So your code should look like this
def list(Integer max) {
params.max
[pilotInstanceList: Pilot.list(params), pilotInstanceTotal: Pilot.count()]
}
Hope this helps you in future if any of you are facing the same problem.
Kam rabwa

PilotController.list(..) returns 10 Entries if no max is given, but you don't set the max, anything else cannot happen.
And You commented pagination out, so there is no way to get the follwing entries.

Related

No such property: propertyName for class: org.grails.orm.hibernate.cfg.HibernatePersistentEntity

im new to grails, and i want to style my f:table in the index.gsp, i created a file _table.gsp, when i execute i get this error :
No such property: propertyName for class: org.grails.orm.hibernate.cfg.HibernatePersistentEntity
index.gsp
<!DOCTYPE html>
<html>
<head>
<meta name="layout" content="main" />
<g:set var="entityName" value="${message(code: 'user.label', default: 'User')}" />
<title><g:message code="default.list.label" args="[entityName]" /></title>
</head>
<body>
<div class="breadcrumbs">
<div class="col-sm-3">
<g:message code="default.link.skip.label" default="Skip to content…"/>
</div>
<div class="col-sm-3">
<a class="home" href="${createLink(uri: '/')}"><g:message code="default.home.label"/></a>
</div>
<div class="col-sm-3">
<g:link class="create" action="create"><g:message code="default.new.label" args="[entityName]" /></g:link>
</div>
</div>
<br>
<br>
<div class="row">
<div class="col-lg-12">
<div class="card">
<div class="card-header">
<strong class="card-title"><g:message code="default.list.label" args="[entityName]" /></strong>
</div>
<div class="card-body">
<div id="pay-invoice">
<div class="card-body">
<div id="list-user" class="content scaffold-list" role="main">
<g:if test="${flash.message}">
<div class="message" role="status">${flash.message}</div>
</g:if>
<f:table collection="${userList}"/>
<div class="pagination">
<g:paginate total="${userCount ?: 0}" />
</div>
</div>
</div>
</div>
</div>
</div> <!-- .card -->
</div>
</div>
</body>
</html>
_table.gsp
<table class="table stripped-table">
<thead>
<tr>
<g:each in="${domainClass}" var="p" status="i">
<g:set var="propTitle">${domainClass.propertyName}.${p.name}.label</g:set>
<g:sortableColumn property="${p.name}" title="${message(code: propTitle, default: p.naturalName)}" />
</g:each>
</tr>
</thead>
<tbody>
<g:each in="${collection}" var="bean" status="i">
<tr class="${(i % 2) == 0 ? 'even' : 'odd'}">
<g:each in="${domainProperties}" var="p" status="j">
<g:if test="${j==0}">
<td><g:link method="GET" resource="${bean}"><f:display bean="${bean}" property="${p.name}" displayStyle="${displayStyle?:'table'}" /></g:link></td>
</g:if>
<g:else>
<td><f:display bean="${bean}" property="${p.name}" displayStyle="${displayStyle?:'table'}" /></td>
</g:else>
</g:each>
</tr>
</g:each>
</tbody>
</table>
User.groovy
class User {
transient securiteService
String username
String password
String nom
String prenom
String email
String tel
static hasMany = [roles : Role]
static constraints = {
username blank: false, unique: true
password blank: false
nom nullable: true
prenom nullable: true
email email:true, nullable:true
tel nullable:true, maxSize:20, matches:/[\+]{0,1}[0-9\s]{3,15}/
}
static mapping = {
password column: '`password`'
sort nom: "asc"
affectations sort : "dateAffectation", order:"desc"
intervention sort : "responsable", order:"desc"
}
}
usercontroller.groovy :
package mylicence
import grails.validation.ValidationException
import static org.springframework.http.HttpStatus.*
import java.security.MessageDigest
class UserController {
UserService userService
static allowedMethods = [save: "POST", update: "PUT", delete: "DELETE"]
def index(Integer max) {
params.max = Math.min(max ?: 10, 100)
respond userService.list(params), model:[userCount: userService.count()]
}
def show(Long id) {
respond userService.get(id)
}
def create() {
respond new User(username: params.username, password: params.password, nom: params.nom, prenom: params.prenom, email: params.email, tel: params.tel)
}
def save(User user) {
if (user == null) {
notFound()
return
}
try {
userService.save(user)
} catch (ValidationException e) {
respond user.errors, view:'create'
return
}
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.created.message', args: [message(code: 'user.label', default: 'User'), user.id])
redirect user
}
'*' { respond user, [status: CREATED] }
}
}
def edit(Long id) {
respond userService.get(id)
}
def update(User user) {
if (user == null) {
notFound()
return
}
try {
userService.save(user)
} catch (ValidationException e) {
respond user.errors, view:'edit'
return
}
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.updated.message', args: [message(code: 'user.label', default: 'User'), user.id])
redirect user
}
'*'{ respond user, [status: OK] }
}
}
def delete(Long id) {
if (id == null) {
notFound()
return
}
userService.delete(id)
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.deleted.message', args: [message(code: 'user.label', default: 'User'), id])
redirect action:"index", method:"GET"
}
'*'{ render status: NO_CONTENT }
}
}
protected void notFound() {
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'user.label', default: 'User'), params.id])
redirect action: "index", method: "GET"
}
'*'{ render status: NOT_FOUND }
}
}
def login() {
}
def handlelogin = {
def hashPassd = params.password
// Find the username
def user = User.findByUsernameAndPassword(params.username, hashPassd)
if (!user) {
flash.message = "User not found for userName: ${params.username}"
redirect(action:'login')
return
} else {
session.user = user
redirect(controller:'user')
}
}
def logout = {
//log.info 'logout'
if(session.user) {
session.user = null
session.invalidate()
redirect(controller:'user', action: 'login')
}
else {
redirect(controller:'user', action: 'login')
}
}
}
i searched every where with no solution, im using grails 3.3.4, groovy 2.4.14, JVM 1.8.0_161
had the same problem here's my solution:
<%# page import="grails.util.GrailsNameUtils" %>
<table >
<thead>
<tr>
<g:each in="${domainProperties}" var="p" status="i">
<g:set var="propTitle">${domainClass.decapitalizedName}.${p.name}.label</g:set>
<g:sortableColumn property="${p.name}" title="${message(code: propTitle, default: grails.util.GrailsNameUtils.getNaturalName(p.name))}" />
</g:each>
</tr>
</thead>
<tbody>
<g:each in="${collection}" var="bean" status="i">
<tr class="${(i % 2) == 0 ? 'even' : 'odd'}">
<g:each in="${domainProperties}" var="p" status="j">
<g:if test="${j==0}">
<td><g:link method="GET" resource="${bean}"><f:display bean="${bean}" property="${p.name}" displayStyle="${displayStyle?:'table'}" /></g:link></td>
</g:if>
<g:else>
<td><f:display bean="${bean}" property="${p.name}" displayStyle="${displayStyle?:'table'}" /></td>
</g:else>
</g:each>
</tr>
</g:each>
</tbody>
</table>
I had to import the grails.util.GrailsNameUtils library to display the name in natural format.

Passing parameters to a form grails

I am new to grails I am trying to pass an object Id to a form. I have domains called Beer and recipe. Beer hasMany recipes and recipe belongsTo beer. I want to create a link to a new recipe from the beer show page passing the beer id in the url in order to create the association. Right now I have been trying to use this link <g:link controller="recpie" action="create" params="[beerid: selectedBeer.id]">Create Recipe</g:link> and retrieve it in the form as a hidden field to submit with the recipe form using <g:field type="text" name="beer.id" value="${beer}"/>.(I know that the hidden property is not set). What am I doing wrong? Also is there a better way to create this association?
Beer Domain Class
class Beer {
String name
String style
Recipe recipe
String toString() {
name
}
static hasMany = [recipe : Recipe]
static constraints = {
}
}
Recipe Domain Class
class Recipe {
String name
Float grainAmount
String yeast
float boilTime
Float hopAmount
float og
float fg
float ogTemp
float fgTemp
float fermTime
Beer beer
static belongsTo = [ beer: Beer]
static constraints = {
beer nullable: true
}
String toString() {
name
}
}
Beer Controller
package com.example
import static org.springframework.http.HttpStatus.*
import grails.transaction.Transactional
#Transactional(readOnly = true)
class BeerController {
static allowedMethods = [save: "POST", update: "PUT", delete: "DELETE"]
def index(Integer max) {
params.max = Math.min(max ?: 10, 100)
respond Beer.list(params), model:[beerCount: Beer.count()]
}
def show(Beer beer) {
respond beer
}
def create() {
respond new Beer(params)
}
#Transactional
def save(Beer beer) {
if (beer == null) {
transactionStatus.setRollbackOnly()
notFound()
return
}
if (beer.hasErrors()) {
transactionStatus.setRollbackOnly()
respond beer.errors, view:'create'
return
}
beer.save flush:true
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.created.message', args: [message(code: 'beer.label', default: 'Beer'), beer.id])
redirect beer
}
'*' { respond beer, [status: CREATED] }
}
}
def edit(Beer beer) {
respond beer
}
#Transactional
def update(Beer beer) {
if (beer == null) {
transactionStatus.setRollbackOnly()
notFound()
return
}
if (beer.hasErrors()) {
transactionStatus.setRollbackOnly()
respond beer.errors, view:'edit'
return
}
beer.save flush:true
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.updated.message', args: [message(code: 'beer.label', default: 'Beer'), beer.id])
redirect beer
}
'*'{ respond beer, [status: OK] }
}
}
#Transactional
def delete(Beer beer) {
if (beer == null) {
transactionStatus.setRollbackOnly()
notFound()
return
}
beer.delete flush:true
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.deleted.message', args: [message(code: 'beer.label', default: 'Beer'), beer.id])
redirect action:"index", method:"GET"
}
'*'{ render status: NO_CONTENT }
}
}
protected void notFound() {
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'beer.label', default: 'Beer'), params.id])
redirect action: "index", method: "GET"
}
'*'{ render status: NOT_FOUND }
}
}
}
Recipe Controller
package com.example
import static org.springframework.http.HttpStatus.*
import grails.transaction.Transactional
#Transactional(readOnly = true)
class RecipeController {
static allowedMethods = [save: "POST", update: "PUT", delete: "DELETE"]
def index(Integer max) {
params.max = Math.min(max ?: 10, 100)
respond Recipe.list(params), model:[recipeCount: Recipe.count()]
}
def show(Recipe recipe) {
respond recipe
}
def create() {
respond new Recipe(params)
}
#Transactional
def save(Recipe recipe) {
if (recipe == null) {
transactionStatus.setRollbackOnly()
notFound()
return
}
if (recipe.hasErrors()) {
transactionStatus.setRollbackOnly()
respond recipe.errors, view:'create'
return
}
recipe.save flush:true
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.created.message', args: [message(code: 'recipe.label', default: 'Recipe'), recipe.id])
redirect recipe
}
'*' { respond recipe, [status: CREATED] }
}
}
def edit(Recipe recipe) {
respond recipe
}
#Transactional
def update(Recipe recipe) {
if (recipe == null) {
transactionStatus.setRollbackOnly()
notFound()
return
}
if (recipe.hasErrors()) {
transactionStatus.setRollbackOnly()
respond recipe.errors, view:'edit'
return
}
recipe.save flush:true
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.updated.message', args: [message(code: 'recipe.label', default: 'Recipe'), recipe.id])
redirect recipe
}
'*'{ respond recipe, [status: OK] }
}
}
#Transactional
def delete(Recipe recipe) {
if (recipe == null) {
transactionStatus.setRollbackOnly()
notFound()
return
}
recipe.delete flush:true
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.deleted.message', args: [message(code: 'recipe.label', default: 'Recipe'), recipe.id])
redirect action:"index", method:"GET"
}
'*'{ render status: NO_CONTENT }
}
}
protected void notFound() {
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'recipe.label', default: 'Recipe'), params.id])
redirect action: "index", method: "GET"
}
'*'{ render status: NOT_FOUND }
}
}
}
Beer/Show GSP
<!DOCTYPE html>
<html>
<head>
<meta name="layout" content="main" />
<g:set var="entityName" value="${message(code: 'beer.label', default: 'Beer')}" />
<title><g:message code="default.show.label" args="[entityName]" /></title>
</head>
<body>
<g:message code="default.link.skip.label" default="Skip to content…"/>
<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>
<li><g:link class="list" action="create" resource="recipe">New Recipe</g:link></li>
</ul>
</div>
<div id="show-beer" class="content scaffold-show" role="main">
<h1><g:message code="default.show.label" args="[entityName]" /></h1>
<g:if test="${flash.message}">
<div class="message" role="status">${flash.message}</div>
</g:if>
<g:link controller="recpie" action="create" resource="recipe" params="[beerid: selectedBeer.id]">Create Recipe</g:link>
<f:display bean="beer" />
<g:form resource="${this.beer}" method="DELETE">
<fieldset class="buttons">
<g:link class="edit" action="edit" resource="${this.beer}"><g:message code="default.button.edit.label" default="Edit" /></g:link>
<input class="delete" type="submit" value="${message(code: 'default.button.delete.label', default: 'Delete')}" onclick="return confirm('${message(code: 'default.button.delete.confirm.message', default: 'Are you sure?')}');" />
</fieldset>
</g:form>
</div>
</body>
</html>
** Recipe/Create GSP**
<%# page import="com.example.Beer" %>
<!DOCTYPE html>
<html>
<head>
<meta name="layout" content="main" />
<g:set var="entityName" value="${message(code: 'recipe.label', default: 'Recipe')}" />
<title><g:message code="default.create.label" args="[entityName]" /></title>
</head>
<body>
<g:message code="default.link.skip.label" default="Skip to content…"/>
<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-recipe" 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="${this.recipe}">
<ul class="errors" role="alert">
<g:eachError bean="${this.recipe}" 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 action="save" name="recipeForm">
<fieldset class="form">
Name:
<g:field type="text" name="name"/>
Grain Amount:
<g:field type="text" name="grainAmount"/>
Yeast:
<g:field type="text" name="yeast"/>
Boil Time:
<g:field type="text" name="boilTime"/>
Hop Amount:
<g:field type="text" name="hopAmount"/>
OG:
<g:field type="text" name="og"/>
FG:
<g:field type="text" name="fg"/>
OG Temp:
<g:field type="text" name="ogTemp"/>
FG Temp:
<g:field type="text" name="fgTemp"/>
Ferment Time:
<g:field type="text" name="fermTime"/>
beer:
<g:hiddenField name="beerid" value="${params.beerid}" />
</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>
You've submitted the beer ID from the beer show paged named beerid so you need to retrieve it from the params on the recipe create page as such:
beer - show.gsp
<g:link controller="recipe" action="create" resource="recipe" params="[beerid: beer.id]">Create Recipe</g:link>
recpie - create.gsp
<g:hiddenField name="beer.id" value="${params.beerid}"/>

Grails empty entry into the database

I have been struggling with trying to create/save multiple instances at once in Grails, now I am almost there with the following code but when I hit save an empty row of options is created, can anyone help me with this
please see these two questions to see what I want to achieve
How to save multiple object from one view using Grails
Grails one to many relationship view
<g:textField name="question" value="${multipleChoiceQuestionInstance?.question}"/><br/>
<div class="fieldcontain ${hasErrors(bean: multipleChoiceQuestionInstance, field: 'options', 'error')} ">
<label for="options">
<g:message code="multipleChoiceQuestion.options.label" default="Options" />
</label>
<ul class="one-to-many">
<g:set var="counter" value="${0}" />
<g:each status="i" in="${multipleChoiceQuestionInstance?.options?}" var="o">
<li>
<g:textField controller="multipleChoiceOption" name="options[${i}].answerOption" action="show" id="${o.id}" value="${o?.encodeAsHTML()}"/>
<g:checkBox name="options[${i}].correctOption" value="${o.correctOption}"/><br/>
</li>
<g:set var="counter" value="${++counter}" />
</g:each>
<li>
<g:textField name="options[${++counter}].answerOption" value=""/>
<g:checkBox name="options[${counter}].correctOption" /><br/>
</li>
<li class="add">
<g:link controller="multipleChoiceOption" action="create" params="['multipleChoiceQuestion.id': multipleChoiceQuestionInstance?.id]">${message(code: 'default.add.label', args: [message(code: 'multipleChoiceOption.label', default: 'MultipleChoiceOption')])}</g:link>
</li>
</ul>
</div>
If you prefer not to click on the link here are the domain classes
Class MultipleChoiceQuestion {
String question
static constraints = {
...
}
static hasMany = [options:MultipleChoiceOption]
class MultipleChoiceOption{
String answerOption
boolean correctOption
MultipleChoiceQuestion question
static constraints = {
...
}
}
}
I am using automatically generated code by grails for the controller, it is as bellow
def create() {
[multipleChoiceQuestionInstance: new MultipleChoiceQuestion(params)]
}
def save() {
println params
def multipleChoiceQuestionInstance = new MultipleChoiceQuestion(params)
if (!multipleChoiceQuestionInstance.save(flush: true)) {
render(view: "create", model: [multipleChoiceQuestionInstance: multipleChoiceQuestionInstance])
return
}
flash.message = message(code: 'default.created.message', args: [message(code: 'multipleChoiceQuestion.label', default: 'MultipleChoiceQuestion'), multipleChoiceQuestionInstance.id])
redirect(action: "show", id: multipleChoiceQuestionInstance.id)
}
def update() {
def multipleChoiceQuestionInstance = MultipleChoiceQuestion.get(params.id)
if (!multipleChoiceQuestionInstance) {
.... //deleted for real estate
return
}
if (params.version) {
//version checking stuff
}
}
multipleChoiceQuestionInstance.properties = params
if (!multipleChoiceQuestionInstance.save(flush: true)) {
render(view: "edit", model: [multipleChoiceQuestionInstance: multipleChoiceQuestionInstance])
return
}
flash.message = message(code: 'default.updated.message', args: [message(code: 'multipleChoiceQuestion.label', default: 'MultipleChoiceQuestion'), multipleChoiceQuestionInstance.id])
redirect(action: "show", id: multipleChoiceQuestionInstance.id)
}
The reason that you are getting an empty row of options is because you are leaving a textfield with name option[counter] blank. This empty value is passed as a parameter to the controller action and it creates a new row with these blank values.
You should remove any blank options before calling
multipleChoiceQuestionInstance.properties = params
You can use something like this :
def emptyOptions = params.options.findAll{!it.answerOption}
params.options.removeAll(emptyOptions)

grails controllers errors

I have this DomainClass:
package cm
class XXX{
String city
String website
static constraints = {
city(nullable: true)
website(nullable: true)
}
static mapping = {
id column:'xxx_id'
city column: 'xxx_city'
website column: 'xxx_website'
table "xxx_XXX"
version false
}
}
The Controller:
class ConferenceController {
static allowedMethods = [save: "POST", update: "POST", delete: "POST"]
def index = {
redirect(action: "list", params: params)
}
def list = {
params.max = Math.min(params.max ? params.int('max') : 10, 100)
[XXXInstanceList: XXX.list(params), XXXInstanceTotal: XXX.count()]
}
def save = {
def XXXInstance= new XXX(params)
if (!XXXInstance.save(flush: true)) {
render view: 'add', model: [XXXInstance: XXXInstance]
return
}
//flash.message = "${message(code: 'default.created.message', args: [message(code: 'person.label', default: 'Person'), personInstance.id])}"
redirect(uri:"/index.gsp")
}
}
and my add.gsp page:
<head>
<title> xXXx</title>
<meta name="layout" content="main2" />
</head>
...
<g:form controller="XXX" action="save">
<g:hasErrors bean="${XXXInstance}">
<div class="errors">
<g:renderErrors bean="${XXXInstance}" as="list" />
</div>
</g:hasErrors>
year
<g:textField name="year" /><br>
website
<g:textField name="website" /><br>
<g:submitButton name="save2" value="Save" />
</g:form></div>
</div>
...
</body>
With this current code, everything works fine, but when a contraint is failed, it is showns the corresponding error but the written values are gone.. I cant figure this out - i'v tried a lot of things, but im sure the solution is as easy as my question -.- Please help.
I think you should check the *.properties file in YOUR_PROJECT\grails-app\i18n folder. They have the definition for translation. Investigate it for a time and refer to the document if need, you will understand how Grails perform translation.
And uncomment the following line in your controller:
//flash.message = "${message(code: 'default.created.message', args: [message(code: 'person.label', default: 'Person'), personInstance.id])}"

Grails: How to make a SAVE button inside the same table and make it work?

I have the create inside the table/list that Grails provides.
Here is a pictures of what I have
As you can see, I create everything on the first row of my table, and then from the 2nd row and on is the actual list.
In the last column of the 2nd row, you can see I have the UPDATE button and a delete button.
The delete button seems to be working fine, but I am having problems with the UPDATE button.
Here is the code for that last column
<g:form>
<g:hiddenField name="id" value="${densityInstance?.id}" />
<g:actionSubmit class="editar" action="update" value="${message(code: 'default.button.editar.label', default: ' ')}" />
<g:actionSubmit class="eliminar" action="delete" value="${message(code: 'default.button.eliminar.label', default: ' ')}" onclick="return confirm('${message(code: 'default.button.delete.confirm.message', default: 'Are you sure you want to delete?')}');" />
</g:form>
And here is what I have for the delete and update in the controller
def delete = {
def densityInstance = Density.get(params.id)
if (densityInstance) {
try {
densityInstance.delete(flush: true)
flash.message = "${message(code: 'default.deleted.message', args: [message(code: 'density.label', default: 'Density'), params.id])}"
redirect(action: "list")
}
catch (org.springframework.dao.DataIntegrityViolationException e) {
flash.message = "${message(code: 'default.not.deleted.message', args: [message(code: 'density.label', default: 'Density'), params.id])}"
redirect(action: "show", id: params.id)
}
}
else {
flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'density.label', default: 'Density'), params.id])}"
redirect(action: "list")
}
}
The DELETE seems to be working fine, and here is the UPDATE, (maybe is the SAVE def that I need to edit, I'm not so sure and that's why I'm asking.
Here is the UPDATE:
def update = {
def densityInstance = Density.get(params.id)
if (densityInstance) {
if (params.version) {
def version = params.version.toLong()
if (densityInstance.version > version) {
densityInstance.errors.rejectValue("version", "default.optimistic.locking.failure", [message(code: 'density.label', default: 'Density')] as Object[], "Another user has updated this Density while you were editing")
render(view: "list", model: [densityInstance: densityInstance])
return
}
}
densityInstance.properties = params
if (!densityInstance.hasErrors() && densityInstance.save(flush: true)) {
flash.message = "${message(code: 'default.updated.message', args: [message(code: 'density.label', default: 'Density'), densityInstance.id])}"
redirect(action: "list", id: densityInstance.id)
}
else {
render(view: "list", model: [densityInstance: densityInstance])
}
}
else {
flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'density.label', default: 'Density'), params.id])}"
redirect(action: "list")
}
}
Thanks in advance!
The g:form you have is only on the final table column, with one hidden form parameter, the id. Delete works, since all it needs is an id. The update requires the rest of the form entries. The editable fields each have a form entry, but they are not enclosed in that g:form, so their data isn't submitted with the form.
You need to make the g:form enclose all the columns of the table row. For example:
<g:form>
<tr>
<td>${densityInstance?.id}<g:hiddenField name="id" value="${densityInstance?.id}" /></td>
<td><g:textField name="commodity" value="${...}"/></td>
...
<td>
<g:actionSubmit class="editar" action="update" value="${message(code: 'default.button.editar.label', default: ' ')}" />
<g:actionSubmit class="eliminar" action="delete" value="${message(code: 'default.button.eliminar.label', default: ' ')}" onclick="return confirm('${message(code: 'default.button.delete.confirm.message', default: 'Are you sure you want to delete?')}');" />
</td>
</tr>
</g:form>

Resources