grails error message in an independent gsp view - grails

In my grails project I've built up a new view in which user can perform a search of entities.
I've created the gsp adding the method search() in controller and automatically creating the gsp as described here
In this gsp there is only one input field and a g:actionSubmit button. If I fill form with correct data everything works well, but if data does not have any correspondance I would see an error message in the view like the validation error messages with popups...but I don't know how to show it, because I'm not using any bean with this gsp.
In addition, after an error, I would render the same view, but with render(view: "search", model: [patientInstance: patientInstance]) the view is the same, but path is /index and not /search...
How can I show an error message? How can I have the right path?
here is the search()
def search()
{
def patientInstance = new Patient()
if(params.patient_textField == "" || params.patient_textField == " " || params.patient_id =="")
{
//here I would like to show message
//the redirect works correctly
redirect(controller: "patient", action: "search")
}
else {
def patientToShow = Patient.findById(params.patient_id)
redirect(controller: "patient", action: "show", params: [id: patientToShow?.id])
}
}
here is the snippet of gsp
<g:form>
<div id="patientDiv">
<label for="patient">
<g:message code="event.patient.label" default="Patient" />
</label>
<input style=" margin: 0px 10px 10px 0px;" type="text" name="patient_textField" id="patient_textField" value="" placeholder="${g.message(code: 'patient.choose', default: 'Insert Patient...')}" />
<input type="hidden" id="patient_id" name="patient_id" value="" />
<g:actionSubmit class="search" value="${g.message(code: 'default.search.label', default: 'Search Patient')}" action="search" ></g:actionSubmit>
</div>
</g:form>
EDIT:
solved problem of path changing render with redirect(controller: "patient", action: "search")

In the error portion of your code you can do flash.error = "Your error message here"
And in the gsp do something like:
<g:if test="${flash.error}">
<div class="alert alert-info">
${flash.message}
</div>
</g:if>
There is already a flash bean in scope. http://grails.org/doc/latest/ref/Controllers/flash.html

Related

Grails - g:field reset and html reset won't clear form/params/session

Using Grails 3.0.9
Making a Clear Form/session button for the filter class. however nothing i do works.
The button is just stuck there, nothing happens
Any help will be appreciated
SupplyController
def index(Integer max) {
params.max = Math.min(max ?: 10, 100)
if (params.name)
session.name = params.name
else if (request.method != "POST")
params.name = session.name
else
session.name = null
def criteria = Supply.createCriteria()
def query = {
and{
if (params.name) {
like ("name", '%' + params.name + '%')
}
}
}
def results = criteria.list(params, query)
respond results, model:[supplyCount: results.getTotalCount()]
}
G:field type of code
<div class="filter">
<h3>Filter:</h3>
<g:form action="index" method="post" >
<label for='name'>Name:</label>
<input type="text" id="name" name="name" value="${session.name}"/><br/>
<span class="button">
<g:submitButton name="index" class="index" value="Apply Filter" /></span>
<g:field type="reset" name="myReset" value="Reset" />
</g:form>
</div>
HTML tag type
<div class="filter">
<h3>Filter:</h3>
<g:form action="index" method="post" >
<label for='name'>Name:</label>
<input type="text" id="name" name="name" value="${session.name}"/><br/>
<span class="button">
<g:submitButton name="index" class="index" value="Apply Filter" /></span>
<input type='reset' value='Reset' />
</g:form>
</div>
An HTML form reset button for a form rests the form to the initial state. In this case back to the values it had when the form loaded. A HTML form reset button does not CLEAR the form or CLEAR the session.
wondering why you are using session for where typicalls form params should be used? In order to clear HTML session you would need to trigger a call back to the originating controller just like you would to post but when it receives via this call. It does a session.invalidate() and then renders same view again. You should try to stick with params for forms. The fact that you have the session information already really no need to post it via a form. Your controller receiving the form would be aware of that same session value.
You could easily create a jquery functionality that you do with a button that triggers and a resetform. jQuery/Javascript function to clear all the fields of a form
Or if that does not work you could try for example in your case:
<g:form ..>
..
<button onClick="clearName();" name="clickme">
</g:form>
<g:javascript>
function clearName() {
$('#name').val();
}
</g:javascript>

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.

Grails - error 404 on form submit using g:actionSubmit

I'm new on Grails and I'm having trouble to do a form submit.
Here is AnimaisController:
package jogoanimais
class AnimaisController {
def index() {
def animalsTreeObj = AnimaisTreeMap.list()
render(view: "show", model: [animalList: animalsTreeObj])
}
def addNode()
{
log.info "add node"
log.info params
}
}
Here is show.gsp
<g:form controller="animais" action="addNode">
<div>Pense em um animal</div>
<g:textField name="myField" value="${myValue}" />
<g:actionSubmit value="OK, próximo" />
<g:each in="${animalList}" var="row" status="i">
<h3> ${row.nodeDescription}, ${row.yesAnswerNode}</h3>
<br/>
</g:each>
</g:form>
After clicking at the submit button, the URL that is requested is "http://localhost:8080/jogoAnimais/animais/addNode" and I get a 404 error.
I've also tried adding "action" do g:actionSubmit but in this case, Grails requested a addNode.gsp.
Does anyone has any idea?
Here's the solution:
GSP:
Add "action" parameter of g:form and a input type "submit" as shown below:
<g:form controller="animais" action="addNode">
<div>Pense em um animal</div>
<div>
<label for="questionToUser">Questão:</label>
<g:textField name="questionToUser" maxlength="50"/>
</div>
<input type="submit" value="Submit">
<g:each in="${animalList}" var="row" status="i">
<h3> ${row.nodeDescription}, ${row.yesAnswerNode}</h3>
<br/>
</g:each>
</g:form>
CONTROLLER:
As mbaird has said, my "addNode" mehtod need to return something, as "render 'ok'"

How to submit form with multi buttons with same value asp.netMvc

I need to build voting web site so, I have couple candidates and below them a vote button,
how I can find which of the buttons was submitted
thanks
Give each of your buttons a name, like so (notice they are both "submit" buttons)::
<input type="submit" name="buttonYes" value="Yes" />
<input type="submit" name="buttonNo" value="No" />
Then, in your controller, capture a parameter for each of the two button names like this:
public ActionResult Index(string buttonYes, string buttonNo) { ... }
You can then tell which button was pressed by checking to see which of these two parameters is not null; the one which is pressed with a have a value equal to the "value" attribute of the button, the other one will be null:
if (buttonYes != null)
{
// Then the yes button was preseed
}
else if (buttonNo != null)
{
// Then the no button was pressed
}
else
{
// Neither button was used to submit the form
// and we got here some other way
}
The reason this works is because the web browser sends the information for the submit button that was pressed as part of the HTTP post to the web server. The button that was not pressed will not be sent with the post, and therefore the parameter will be null.
There are lots of ways to rewrite and optimzie this, but this is the essence of it and shows the fundamentals that are at work--you can play with it from there.
I wouldn't use the button value, I would set it up so that the url used to do the post encodes the vote itself. You could do this a couple of ways.
Use links
<div class="left">
<img src="/images/candidate/#Model.Candidates[0].ID" alt="#Model.Candidates[0].Name" />
#Html.ActionLink( "Vote for " + Model.Candidates[0].Name, "count", "vote" )
</div>
<div class="right">
<img src="/images/candidate/#Model.Candidates[1].ID" alt="#Model.Candidates[1].Name" />
#Html.ActionLink( "Vote for " + Model.Candidates[1].Name, "count", "vote" )
</div>
Use separate forms
<div class="left">
#using (Html.BeginForm( "count", "vote", new { id = Model.Candidates[0].ID } ))
{
<img src="/images/candidate/#Model.Candidates[0].ID" alt="#Model.Candidates[0].Name" />
<input type="submit" value="Vote" />
}
</div>
<div class="right">
#using (Html.BeginForm( "count", "vote", new { id = Model.Candidates[1].ID } ))
{
<img src="/images/candidate/#Model.Candidates[1].ID" alt="#Model.Candidates[1].Name" />
<input type="submit" value="Vote" />
}
</div>
Either of the above can be adapted to work with AJAX as well. Note, if you care, you'll need to build in some mechanism to detect vote fraud, e.g., add a one-time nonce to the url to verify that it isn't used more than once; track the number of times a user has voted if they are authenticated, etc.

View issue - multiple 'delete forms'

I have a really strange ‘bug’. I use this in my view:
<% foreach (var QualitativeGlobalFeatureValue in Model.PossibleValues)
{ %>
<% using (Html.BeginForm("DeleteQualitativeGlobalFeatureValue", "Features", FormMethod.Post, new { #class = "deleteForm" }))
{ %>
<%= QualitativeGlobalFeatureValue.Value %>
<%= Html.ActionLink("Edit", "QualitativeGlobalFeatureValueForm", new { FeatureId = Model.Id, Id = QualitativeGlobalFeatureValue.Id })%>
<%= Html.Hidden("QualitativeGlobalFeatureValueId", QualitativeGlobalFeatureValue.Id)%>
<%= QualitativeGlobalFeatureValue.Id %>
<%= Html.Hidden("FeatureId", Model.Id)%>
<input type="submit" value="Delete" class="link_button" />
<% } %>
<% } %>
This produces a bunch of forms which post to an action which then redirect to an action which in turn produces this view.
Here is some HTML:
<form action="/Features/DeleteQualitativeGlobalFeatureValue" class="deleteForm" method="post">b
Edit
<input id="QualitativeGlobalFeatureValueId" name="QualitativeGlobalFeatureValueId" value="3004" type="hidden">
3004
<input id="FeatureId" name="FeatureId" value="2103" type="hidden">
<input value="Delete" class="link_button" type="submit">
</form><form action="/Features/DeleteQualitativeGlobalFeatureValue" class="deleteForm" method="post">aa
Edit
<input id="QualitativeGlobalFeatureValueId" name="QualitativeGlobalFeatureValueId" value="9010" type="hidden">
9010
<input id="FeatureId" name="FeatureId" value="2103" type="hidden">
<input value="Delete" class="link_button" type="submit">
</form>
Now if I delete the value with the Id 9010 the resulting HTML is as follows:
<form action="/Features/DeleteQualitativeGlobalFeatureValue" class="deleteForm" method="post">b
Edit
<input id="QualitativeGlobalFeatureValueId" name="QualitativeGlobalFeatureValueId" value="9010" type="hidden">
3004
<input id="FeatureId" name="FeatureId" value="2103" type="hidden">
<input value="Delete" class="link_button" type="submit">
</form>
For some unexplainable reason it contains value="9010" rather than value="3004" although it uses the code QualitativeGlobalFeatureValue.Id
It just does not make sense. Is this some browser/caching issue? – I am using Firefox. Thanks!
Best wishes,
Christian
PS:
Actions:
[MembersOnlyAttribute]
[AcceptVerbs(HttpVerbs.Get)]
public ViewResult GlobalQualitativeFeature(string Id)
{
QualitativeGlobalFeature QualitativeGlobalFeature = null;
if (TempData["ViewData"] != null)
{
ViewData = TempData["ViewData"] as ViewDataDictionary;
}
try
{
QualitativeGlobalFeature = FeatureService.GetQualitativeGlobalFeature(Id);
}
catch (Exception e)
{
ModelState.AddModelError("Exception", e.Message);
}
return View("GlobalQualitativeFeature", QualitativeGlobalFeature);
}
[MembersOnlyAttribute]
[AcceptVerbs(HttpVerbs.Post)]
public RedirectToRouteResult DeleteQualitativeGlobalFeatureValue(string QualitativeGlobalFeatureValueId, string FeatureId)
{
try
{
FeatureService.GetQualitativeGlobalFeatureValueRepository().DbContext.BeginTransaction();
FeatureService.DeleteQualitativeGlobalFeatureValue(QualitativeGlobalFeatureValueId);
FeatureService.GetQualitativeGlobalFeatureValueRepository().DbContext.CommitTransaction();
}
catch (Exception e)
{
ModelState.AddModelError("Exception", e.Message);
FeatureService.GetQualitativeGlobalFeatureValueRepository().DbContext.RollbackTransaction();
}
TempData["ViewData"] = ViewData;
return RedirectToAction("GlobalQualitativeFeature", new { Id = FeatureId });
}
I suspect the following. You click on the delete button for the 9010. The form is posted and the POST request contains QualitativeGlobalFeatureValueId=9010. In the controller action the same view is rendered. Here's the gotcha. When you write this:
<%= Html.Hidden(
"QualitativeGlobalFeatureValueId",
QualitativeGlobalFeatureValue.Id)
%>
The HTML helper (and not only this one) will first look if there's a request parameter with the same name as the name of the field (QualitativeGlobalFeatureValueId) and will use this value instead of the one you specified as the second argument (that's the way it is, don't ask my why, it's by design). So to fix this the only way is to manually render the hidden field:
<input
id="QualitativeGlobalFeatureValueId"
name="QualitativeGlobalFeatureValueId"
value="<%= QualitativeGlobalFeatureValue.Id %>"
type="hidden"
/>
You can put breakpoints in the markup and debug as it renders through, though it doesn't allow putting breakpoints on client markup or <% lines, so you need to find a line continuation.
Are you sure that it isn't a sort reordering or something like that, maybe the results aren't sorted, and that result is later on?
HTH.

Resources