Is it possible to pass 'params' in a redirect at the end of a Webflow? Basically the purpose of this variable or param passing from controller to controller is this, I want to have a variable or ${param.xyz} available on the view page only if the flow has been completed.
class Example1Controller{
def startFlow = {
begin {
....
}
....
....
finished {
action {
flash.message = 'success'
}
redirect(controller: 'example2', action: 'myaccount', params: [author: "Stephen King"])
}
}
}
OTHER CONTROLLER
class Example2Controller{
def myaccount() {
def here = $params.author
return [me:here]
}
}
GSP VIEW
<html>
<body>
<g:if test="${params.me}">
<p>This is what I want to display: **${me}**</p>
<p>But it must come from the first controller, from the flow.</p>
</g:if>
</body>
</html>
Basically the purpose of all this variable passing from controller to controller is this. I want to have a variable or ${param.} available on the view page only if the flow has been completed.
You can use hiddenField .
<g:hiddenField name="myField" value="myValue" />
you can pass value from Example1Controller to Example1Gsp(as hideenField) and from that GSP you can get value in your Example2Controller.
If I remember right, we did this before but we used the flow scope/ flow variables. Something like:
def myFlow = {
fin {
redirect: (controller: "xxx", action: "yyy", params: [someValue: flow.someValue])
}
}
Then, in the receiving end, something like:
def yyy = {
[ aaa: params.someValue ]
}
Related
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;
}
I am using grails and i have a basic form remote
<g:formRemote name="add" onSuccess="close();" onFailure="dispayErrors();\"
url="[controller: ctx, action: 'insert']" method="POST" class="add">
//Some inputs + submit button
</g:formRemote>
My question is what shoud the insert method return for so that onFailure is triggered?
Thanx
Change the controller action (temporarily I presume) to
def insert = {
render status: HttpServletResponse.SC_INTERNAL_SERVER_ERROR
// This also works
//response.sendError HttpServletResponse.SC_INTERNAL_SERVER_ERROR
}
If you're using Grails 2.0 it is recommended to define your action as a method rather than a closure:
def insert() {
render status: HttpServletResponse.SC_INTERNAL_SERVER_ERROR
}
This is in the gsp
<g:if test="${hasError}">
<div class="errors">
<g:renderErrors bean="${eventInstance}" />
</div>
</g:if>
<g:else >
<div id="messageBox" class="message" style="display:none;">
<g:message code="legalevent.save.success" args="[entityName]" default="Event saved successfully" />
</div>
</g:else>
<g:formRemote name="eventForm" id="eventForm" url="[controller : 'search', action : 'saveLegalEvent']"
update="eventFormDiv" action="${createLink(controller: 'search', action: 'saveLegalEvent')}" method="POST"
onSuccess="jQuery('#messageBox').show()">
I am rendering a page for update with this :
def saveLegalEvent = {
def paramsView = params
def eventPattern = /(event\.).*/
def event = LegalEvent.findByLevId(params["levId"])
def corrTxt = params["corrTxt"] as CorrectionText
if(corrTxt.getCorrId()){
corrTxt = CorrectionText.findByCorrId(corrTxt.getCorrId())
}
event.setCorrTxt(corrTxt)
event.properties = params["event"]
def dataList = []
def hasError = false
def validated = event.validate()
validated &= event.validateHistoryParams()
if(validated)
event.save(flush:true)
else
hasError = true
def errorsView = event.errors
render(view:'leform', model:[attributeDataInstanceList:event.tags, lecInstance:event.leCode, eventInstance:event, hasError: hasError])
}
validateHistoryParams validate some more params that are usually not needed in the domain class.
def validateHistoryParams = { ->
if(!changeRef || !changeRef.trim()) {
this.errors.rejectValue('changeRef', 'event.changeRef.blank')
}
if(!corrTxt || !(corrTxt.corrTxt.trim() || corrTxt.corrId )) {
this.errors.rejectValue('corrTxt', 'event.corrTxt.null')
}
!(this.hasErrors())
}
The problem with all this is that the errors are not rendered in the gsp.
All other tags are rendered fine, when debugging I can see that the errors are actually in the error stack. But in the end, the tag isn't rendering them.
As you can see, there is no redirection, so I can't understand why the errors would somehow be erased between the response creation and the rendering ...
In your Groovy code, parameter returned is named hasError, and GSP checks for hasErrors. I'd recommend not to use extra variables, and just query the bean itself in GSP.
I also believe that you need to have that errors div inside the formRemote element in order to re-render after form submission.
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.
Using markup with the render is not adding the form tag.
I tried this with contentType "text/html", "txt/xml" and it does not work.
I have this in my controller:
def myTest= {
render(contentType: "text/plain") {
div(id:"myDiv") {
p "somess text inside the div"
form (action:'get') {
p "inside form"
}
}
}
And I'm getting this:
<div id='myDiv'><p>somess text inside the div</p><p>inside form</p></div>
I want this:
<div id='myDiv'><p>somess text inside the div</p><form><p>inside form</p></form></div>
Does anybody know why is not adding the form and how to add it?
Thanks,
Federico
i found this problem earlier and the work around was to use the builder directly
def test = {
def sw = new StringWriter()
def b = new MarkupBuilder(sw)
b.html(contentType: "text/html") {
div(id: "myDiv") {
p "somess text inside the div"
b.form(action: 'get') {
p "inside form"
}
}
}
render sw
}
will render the following HTML
<html contentType='text/html'>
<div id='myDiv'>
<p>somess text inside the div</p>
<form action='get'>
<p>inside form</p>
</form>
</div>
</html>