Grails pagination not working - grails

I've been a week trying to fix this pagination problem, but with no good results,
I have this in my controller
PatientController{
def show(Long id) {
def patientInstance = Patient.get(id)
if (!patientInstance) {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'patient.label', default: 'Patient'), id])
return
}
def historyInstance = History.findAllByPatient(patientInstance)
def total = historyInstance.size()
[historyInstance: historyInstance,patientInstance: patientInstance,historyInstanceTotal: total]
}
}
And I have this code on the view
<g:each in="${historyInstance}" var="historyInstances" status="i">
...
</g:each>
<div class="pagination">
<g:paginate total="${historyInstanceTotal}"/>
</div>
I used params, the max on the <g:paginate>, I tried everything but with no result it always shows the whole set of History in the view.

You need to pass your params to the finder you're using, otherwise it won't know how to paginate. The <g:paginate> tag is only for displaying pagination links, not actually performing the pagination. Also the total will need to use a countBy because the result set will be limited to the current page of results.
def historyInstance = History.findAllByPatient(patientInstance, params)
def total = History.countByPatient(patientInstance)

Related

Grails validation with composite key

I'm running into a complex scenario where we are using a legacy database with composite keys and the client wants to be able alter two of the databases pks, "expenseDate" and "adjustmentNumber". In order to be able to change the pks, I've have to use a HQL query. Now of course this has caused another slew of issues with validation. My work around was to populate a domain so that I could validate against it.
So far everything works fine until we have a validation error that I'd like to return to the UI.
I have the following URL which uses the recoveryDetail controller and the edit action to render the page.
http://localhost:8080/pisr/recoveryDetail/edit?division=ALBANY&peid=PI0003&orgkey=14046701&expenseDate=07-22-2015&adjustmentNumber=1
Edit action
def edit() {
//Parse clean url expense date
params.expenseDate = new SimpleDateFormat('MM-dd-yyyy').parse(params.expenseDate)
def recoveryDetailInstance = RecoveryDetail.get(new RecoveryDetail(params))
if(recoveryDetailInstance == null) {
redirect(uri:'/')
return
}
[recoveryDetailInstance: recoveryDetailInstance, disabled: isdisabled(recoveryDetailInstance.batchOverride)]
}
And the following update action.
Update action
#Transactional
def update() {
params.pk_expenseDate = getDateParser(params.pk_expenseDate)
params.expenseDate = getDateParser(params.expenseDate)
params.adjustmentNumber = getAdjustementNumber(params)
RecoveryDetail recoveryDetailInstance = new RecoveryDetail(params);
recoveryDetailInstance.division = params.pk_division
recoveryDetailInstance.peid = params.pk_peid
recoveryDetailInstance.orgkey = params.pk_orgkey
recoveryDetailInstance .validate()
if(recoveryDetailInstance .hasErrors()) {
flash.message = "test"
respond view: "edit", model:[recoveryDetailInstance:recoveryDetailInstance]
return
} else {
def sqlParams = [
pk_division:params.pk_division,
pk_peid:params.pk_peid,
pk_orgkey:params.pk_orgkey,
pk_expenseDate:params.pk_expenseDate,
pk_adjustmentNumber:params.int('pk_adjustmentNumber'),
approved:YesNoTypes.valueOf(params.approved),
batchOverride:YesNoTypes.valueOf(params.batchOverride),
adjustmentFlag:params.adjustmentFlag,
adjustmentNumber:params.adjustmentNumber,
projectHours:new BigDecimal(params.projectHours),
percentEffort:new BigDecimal(params.percentEffort),
totalHours:new BigDecimal(params.totalHours),
expenseDate:params.expenseDate
]
RecoveryDetail.executeUpdate(recoveryDetailQuery, sqlParams)
}
Edit gsp
<g:form class="form-horizontal" url="[resource:recoveryDetailInstance, action:'update']" method="PUT">
<!-- hidden fields contain params from url (composite key)-->
<g:hiddenField name="pk_division" value="${recoveryDetailInstance?.division}"/>
<g:hiddenField name="pk_peid" value="${recoveryDetailInstance?.peid}"/>
<g:hiddenField name="pk_orgkey" value="${recoveryDetailInstance?.orgkey}"/>
<g:hiddenField name="pk_expenseDate" value="${formatDate(format:'MM/dd/yyyy',date:recoveryDetailInstance?.expenseDate)}" />
<g:hiddenField name="pk_adjustmentNumber" value="${recoveryDetailInstance?.adjustmentNumber}"/>
<div class="row">
<div class="col-md-6">
<g:render template="form" model="[recoveryDetailInstance: recoveryDetailInstance, 'mode':'edit']"/>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<g:actionSubmit class="btn btn-primary" action="update" disabled="${disabled}" value="${message(code: 'default.button.update.label', default: 'Update')}"/>
</div>
</div>
</g:form>
The problem
When a user causes a validation error that triggers a server side response, I run into the following problems with the different return types.
redirect - this is returning the flash message, but redirects the gsp to the edit action which in turn fires the initializer query and replaces all the form data with the original data.
Example -
redirect (controller:"recoveryDetail", action:"edit", params:["division":params.pk_division, "peid":params.pk_peid, "orgkey": params.pk_orgkey, "expenseDate":params.expenseDate.format("MM-dd-yyyy"), "adjustmentNumber":params.adjustmentNumber])
respond - So I assumed I needed to just use respond, well it resulted in the following.
URL was changed to http://localhost:8080/pisr/recoveryDetail/update dropping all parameters and a 404 page was returned.
Example
flash.message = "test"
respond view: "edit", model:[recoverDetailInstance:recoverDetailInstance]
return
So my question
How do I throw a server side validation error and return it to the page with the data entered by the user?
You may add the parameters back into the redirect or render call.
redirect (..., params: params)
https://grails.github.io/grails-doc/latest/ref/Controllers/redirect.html
Also, I'd suggest using a service instead of the controller method. Services are already transactional. I would also throw an exception if the hasErrors is true. The exception message or object can be your payload back to the user.
Solution was to use render without the use of params like so.
if(recoveryDetailInstance.hasErrors()) {
render view: "edit", model:[recoveryDetailInstance:recoveryDetailInstance]
return
}

AJAX Response Rails 4 Does Not Return In Text Field

I've just started coding in Rails 4, so I may need very specific instruction. I'm using AJAX to take user input from a text field, modify it (for simplicity's sake I'm just adding " yay!" on the end of it), and return the response as a string to the text field.
I believe I am sending my AJAX request correctly, but something in my controller or view isn't modifying or displaying the result.
Here is my code:
View (solve.html.erb):
<head>
<script>
function myFunction() {
var xmlhttp = new XMLHttpRequest();
var url = "solve";
var params = "field1=" + document.getElementById("field1").value;
xmlhttp.onreadystatechange=function() {
if (xmlhttp.readyState==4 && xmlhttp.status==200) {
document.getElementById("field1").innerHTML=xmlhttp.responseText;
}
}
xmlhttp.open("GET", url + "?" + params, true);
xmlhttp.send();
}
</script>
</head>
<h1>Solve!</h1>
<p>Type it in, type it in.</p>
<div class="col-lg-6">
<div class="input-group">
<input id="field1" type="text" class="form-control" placeholder="1+1">
<span class="input-group-btn">
<button class="btn btn-default" type="button" onclick="myFunction()">Solve</button>
</span>
</div>
</div>
Routes (routes.rb):
resources :equations
#rest of my routes code
get 'solve' => 'equations#solve'
Controller (equations_controller.rb):
class EquationsController < ApplicationController
def solve
if request.post?
new_var = params[:field1]
other_var = "#{new_var} yay!"
return other_var
end
end
end
If you have any questions, I'll get right back to you. Thank you so much for your help! Anything is greatly appreciated.
You're making a GET request but checking if the request is POST in your EquationsController#solve method. Update controller code as follows:
class EquationsController < ApplicationController
def solve
if request.get? # Change to `request.get?`
new_var = params[:field1]
other_var = "#{new_var} yay!"
return other_var
end
end
end
Then the second problem is, you should be writing the output instead of returning it from the controller. As you are expecting text/plain mime type, you should render text instead:
class EquationsController < ApplicationController
def solve
if request.get?
new_var = params[:field1]
other_var = "#{new_var} yay!"
render plain: other_var # Change to `render plain: other_var`
end
end
end
This however, is not the recommended way to handle AJAX requests/responses in Rails. Please refer to: Working with JavaScript in Rails. Also, please see The response object for details on the same.
Try this in myFunction()
if (xmlhttp.readyState==4 && xmlhttp.status==200) {
document.getElementById("field1").value = xmlhttp.responseText;
}
I think this works
ok, I think the controller's action is rendering the default 'solve.html.erb' view. so you should return just the value you wish like
class EquationsController < ApplicationController
def solve
if request.post?
new_var = params[:field1]
other_var = "#{new_var} yay!"
render html: other_var
end
end
end
and in js
if (xmlhttp.readyState==4 && xmlhttp.status==200) {
document.getElementById("field1").value = xmlhttp.responseText;
}

Creating a new entry with preset values

Solved. I really don't know what I did, but it worked. One of those moments...
My domain object is "Actiune". I want to add a new entry with 4 preset fields from another entry that has the given id to "createNewEtapa" method. So I query that entry (with the id) and get it's values, preset them in the form and the hit save but it does not work. The save will not work.
What am I doing wrong ? I've been going around this for hours. Please help again stackOverflow :)
If you don't feel like checking all the code, please just let me know how is this done or link me a example :)
Thx!
These are the relevalt parts of my code
This is my GSP form:
<g:form action="save" enctype="multipart/form-data">
<fieldset class="form">
<g:applyLayout name="form">
<tmpl:/templates/form />
</g:applyLayout>
</fieldset>
<fieldset class="buttons">
<g:submitButton name="create" class="save"
value="${message(code: 'default.button.adauga.label', default: 'Adauga')}" />
<g:actionSubmit name="create" class="save" action="savenew" value="Adauga2" />
</fieldset>
</g:form>
This is my controller:
def create(Long id){
def actiuneInstance = Actiune.findById(id)
def c = Actiune.createCriteria()
def instanceList = c {
eq("idActiune", actiuneInstance.idActiune)
order("termenPornire", "asc")
}
params.idActiune = actiuneInstance.idActiune
params.tema = actiuneInstance.tema
params.firma = actiuneInstance.firma
params.user = User.findById(springSecurityService.currentUser.id)
[instance: new Actiune(params)]
}
def save() {
def actiuneInstance = new Actiune(params)
actiuneInstance.user = User.findById(springSecurityService.currentUser.id)
actiuneInstance.termenPornire = new Date()
def actiuneBD = Actiune.findByIdActiune(params.idActiune)
actiuneInstance.idActiune = actiuneBD.idActiune
actiuneInstance.tema = actiuneBD.tema
actiuneInstance.firma = actiuneBD.firma
print "in params " + params
print "\\"
print "in save... " + actiuneInstance.properties
if (!actiuneInstance.save(flush: true)) {
render(view: "create", model: [firInstance: actiuneInstance])
return
}
flash.message = message(code: 'default.created.message', args: [message(code: 'actiune.label', default: 'Actiune'), actiuneInstance.idActiune])
redirect(action: "completeShow", id: actiuneInstance.id)
}
This is the output from the print statements in the save() method
*...*
in params [termenLimita_month:11, termenPornire_month:11, termenPornire_day:1, documentPath:, tema:Promotie A, termenLimita_day:1, _action_savenew:Adauga2, id:, observatii:uuu, termenLimita:date.struct, termenPornire_year:2012, etapa.id:1, etapa:[id:1], contact.id:1, contact:[id:1], termenPornire:date.struct, firma:Google, idActiune:zt8h, termenLimita_year:2012, action:save, controller:actiune]
\
....
in save... [user:Flavian, termenPornire:Thu Nov 01 22:57:45 EET 2012, contact:null, documentPath:null, temaId:1, etapaId:null, firmaId:3, firma:Google, contactId:null, termenLimita:null, idActiune:zt8h, observatii:null, userId:null, etapa:null, tema:Promotie A]
Call actiuneInstance.validate() and then look at the actiuneInstance.errors object to see the result of any validation errors on your object.

Grails - custom Flash.message rendering

I am running a query to check if an entity id exists for multiple account ids. If the result set is not null, then I need to either throw an error or display a flash message.
The code for the method is as below:
def save() {
def SAMLInfoInstance = new SAMLInfo(params)
def account = Account.get(params?.accountId)
SAMLInfoInstance.setAccount(account)
def samlInfoInstanceList = SAMLInfo.executeQuery("from SAMLInfo " +
" where account.id <> ? " +
" and entityId = ?", [SAMLInfoInstance.accountId, SAMLInfoInstance.entityId])
if (samlInfoInstanceList?.size > 0){
flash.message = message(code: 'test.not.created.message', args: [message(code: 'SAMLInfo.label', default: 'SAMLInfo'), SAMLInfoInstance.entityId])
/*flash.message = "default.not.created.message"
flash.args = ["SAMLInfo", SAMLInfoInstance.entityId]
flash.default = "SAMLInfo cannot be created"
*/
render(view: "create", model: [SAMLInfoInstance: SAMLInfoInstance])
return
}
if (!SAMLInfoInstance.save(flush: true)) {
render(view: "create", model: [SAMLInfoInstance: SAMLInfoInstance])
return
}
flash.message = message(code: 'default.created.message', args: [message(code: 'SAMLInfo.label', default: 'SAMLInfo'), SAMLInfoInstance.entityId])
redirect(action: "list", id: SAMLInfoInstance.account.id)
}
In my view I render the flash message and the errors in the following manner:
<g:if test="${flash.message}">
<br/>
<div class="message" role="status">
<g:message code="${flash.message}" args="${flash.args}" default="${flash.default}"/>
</div>
<br/>
</g:if>
<br/>
<g:renderErrors bean="${SAMLInfoInstance}" as="list" />
In my message.properties file, I have the following line:
test.not.created.message=The SP url {1} is not allowed for this account. Please enter a different value.
When I run this code, the flash message displays as the string I pass as message i.e. "test.not.created.message". Also, this string is passed on to display whenever I navigate to any other page which displays flash.message.
I am new to grails and groovy and would appreciate any help with this.
Thanks!
2 problems then:
1 - the message is not being retrieved from your message.properties:
You must have other message.properties files in your project. Give it a check. Because if it's not found, grails shows the code itself instead of the message, since it did not find one. Maybe it's looking for your message in some other properties file, like the one specific for your Locale (ex: pt_BR or en_US). Other than that, you're doing it right using the message(code:...) construct.
2 - Your flash message doesn't disappear:
Instead of flash.message, use request.message.
I think the example you want to follow is here.
You only need to resolve the message once ie in the controller or in the view.
So in the controller:
flash.message = "test.not.created.message"
flash.args = ["SAMLInfo"]
flash.default = "<default text>"
And in the view:
<g:message code="${flash.message}" args="${flash.args}"
default="${flash.default}"/>
The flash scope is cleared at the end of the next request which may explain why you still see the message on the next page.

Rendering command validation errors across a redirect

I cannot render the errors from my command object. It does the job well but my .gsp view does not render the errors I raise.
Here is my controller action:
def handleModifyProfile2 = { CreditProviderModificationCommand cpmc -> // bind params to the command object
if (cpmc.hasErrors()) {
flash.message = "Error modifying your profile:"
redirect(action: "modifyProfile", params: [creditProvider : cpmc])
} ...
Here is how I try to render the errors in my .gsp view:
<g:hasErrors bean="${creditProvider}">
<div class="errors">
<g:renderErrors bean="${creditProvider}" as="list" />
</div>
</g:hasErrors>
How can I get the errors to be displayed in the view?
You can't send the command across in a redirect using params. You have a couple options:
render() in the error condition instead of redirect()ing:
if(cpmc.hasErrors()) {
render(view: 'profile', model: [creditProvider: cpmc])
}
This is the most common idiom for what you're doing.
Store the command in the session to persist it across the redirect:
if(cpmc.hasErrors()) {
session.cpmc = cpmc
redirect(...)
}
// and in your action
def cpmc = session.cpmc ?: null
render(view: 'profile', model: [creditProvider: cpmc])
This option is somewhat questionable. If not done correctly, you can pollute the session and leave objects hanging around, taking up memory. If done correctly, though, it can be a decent way to implement a post-redirect-get.
With Grails 3 (I don't know if this worked earlier) it's possible to use the flash for this. According to the documentation, the flash will be "cleared at the end of the next request".
I like to use a pattern like this:
def save(MyDomain myDomain) {
if (myDomain.validate()) {
myDomain.save()
} else {
flash.errors = myDomain.errors
}
redirect(action: 'edit', id: myDomain.id)
}
def edit(MyDomain myDomain) {
if (flash.errors) {
myDomain.errors = (Errors) flash.errors
}
return [myDomain: myDomain]
}
I don't like to use render() for this kind of error handling, because it makes URLs shown in the browser inconsistent with the shown page. This breaks when users set bookmarks, for example.

Resources