Grails render view of different controller - grails

My question is similar to this following post
Render a view of another controller
I have a TestConfigController my question is what can I do in case validation fails and I want to render controller:test and view:edit rather then controller:testCOnfig and view:edit
def save() {
def testConfigInstance = new TestConfig(params)
if (!testConfigInstance.save(flush: true)) {
/*Rather then view:"edit" i want view:"/test/edit" which does not work */
render(view:"edit", model: [testConfigInstance: testConfigInstance],id:params.test.id)
return
}
println "+++++++++++++++++++++++++"
flash.message = message(code: 'Data successfully saved', args: [message(code: 'testConfig.label', default: 'Successfully saved')])
redirect(action: "edit", controller:"test", id:params.test.id)
}
Any pointers? I have already looked into grails redirect which does not have "model" param and thus can not pass the validation errors to the view
Also I have looked in to grails render which does not have controller param so that I can go back to different controller!
Please let me know if more detail/code is needed
EDIT
Following happens while using one of the two things
render(view:"/test/edit", model: [testConfigInstance: testConfigInstance],id:params['test.id'])
The code above renders the page /test/edit with no reference to testid eventually erroring out saying "test.id" can not be null.. (means its rendering /test/edit and not /test/edit/1)
render(view:"/test/edit/"+params['test.id'], model: [testConfigInstance: testConfigInstance],id:params['test.id'])
The code above leads to following error
The requested resource (/EasyTha/WEB-INF/grails-app/views/test/edit/1.jsp) is not available.
Either one of the above code renders just "/test/edit" no id at the end, thus eventually erroring out saying test.id can not be null.

The value of id that you are trying to append in the view path should be a part of the model map. The values that you provide in the model map are available in the view that is rendered.
In the first option that you tried, the id parameter doesn't make any difference as the render method doesn't use any 'id' parameter (the redirect method uses the id parameter to generate the redirect url).
Your code snippet should be something like this:
render(view:"/test/edit", model: [testConfigInstance: testConfigInstance, id:params['test.id']])
The render method that you are using here doesn't redirect you to some other action. render just prints the parsed viewName to the output stream. Eg. render(view:"/test/edit") just renders the edit.gsp view. It isn't actually redirecting you to the edit action of test controller. Therefore, just passing the id in the model map won't give you access to the testInstance on the view. You will have to get the testInstance By id and pass it to the view in the model map
render(view:"/test/edit", model: [testConfigInstance: testConfigInstance, testInstance: Test.get(params['test.id'] as Long)])

Anuj Arora is right:
If you just want to render an arbitrary view you can use the full path to the view related to the grails-app/view folder:
In your case:
render(view:"/test/edit", model: [testConfigInstance: testConfigInstance],id:params.test.id)
should work.

If you are only wanting to render the view /test/edit, then the call render(view:'/test/edit',...) should be all you need.
If instead, you also want to include some of the processing from the TestController and edit action, then look at the chain() call. It has a model parameter where you can pass the validation errors and controller/action parameters to redirect to the other controller.

Related

How to redirect from one action to another when action parameter are different?

I have a controller with Index and Add actions; both of which have different parameters. Index just loads the form and after form gets filled "Add" saves the entries to the database. Saving is working fine. However, when there are some error while adding, I want to show the error in the same page and stay on that page. When i retrun view it tries to render \add (ie.Add action) and it throws error as it cannot find /Add page. I am using ValidationMessage for showing error. How to redirect from one action to another when action parameter are different?
Try this:
return View("Index", model)

Grails disallow normal create

Grails noob here. I am build a simple grails app where I have the default create/ edit / list / show pages for a Product domain object. I also have the ProductController. The create method by default does this:
def create() {
[productInstance: new Product(params)]
}
My understanding is this will take me to the create page. And there will be nothing in the params object so everything will be blank.
I want to change the behaviour so that the when the create() method is invoked, a pop up is returned to the User: Sorry you are not allowed to create new data.
The user will stay on the same page and the only thing that will happen is the pop up.
How do I do this without using JavaScript?
Thanks
If the create method is not allowed, why not just remove the create() method from the controller, delete the create.gsp page and remove the 'New' button from the list page?
If you do want to offer a 'New' button and display a popup message that says you can't use the button, that is probably easiest done in javascript.
If you can just display the message in the default grails message panel rather than in a popup, then change the controller method to
def create() {
flash.message = "Sorry you are not allowed to create new data."
redirect(action: "list")
}
Prior to sending the user to the GSP view, you should make a decision in the controller, if the user is allowed to execute the create action. In your controller this could be something simple like:
params.allowed = false
The result of this decision is then passed to you GSP where you can evaluate it inside the GSP using something like:
<g:if test="${params.allowed == false}">
Alert: you are not allowed...
</g:if>
For the alerts, there are good looking alternatives to javascript like: http://getbootstrap.com/components/#alerts

How to call to another controller passing all the params in Grails (to update the associated table in the same form)

I'm working with the domain class Alojamiento, and its generated controller and views. The next code works:
I have included in the form of a view another form:
<g:render template="../caracteristicas/form" bean="${params.caracteristicasInstance}" />
Now, the edit action of the controller has:
def alojamientoInstance = Alojamiento.get(id)
def caracteristicasInstance = alojamientoInstance.caracteristicas
[caracteristicasInstance: caracteristicasInstance,
And to the update action of the controller:
def caracteristicasInstance = Caracteristicas.get(id)
caracteristicasInstance.properties = params
caracteristicasInstance.save(flush: true)
As I said, the above code works, but it is not protected against errors, so I'm trying to use the update action of CaracteristicasController (I'm following this approach: http://stuff4j.blogspot.com.es/2011/04/calling-controller-method-from-another.html). The next code does NOT work, but I think it explain itself what I'm trying:
CaracteristicasController caracteristicasController = new CaracteristicasController()
CaracteristicasController.properties = params
CaracteristicasController.params.doNotRedirect = 'true' // See: http://stuff4j.blogspot.com.es/2011/04/calling-controller-method-from-another.html
CaracteristicasController.update()
By the way, the error of Grails is: "Cannot set read-only property: properties"
UPDATE 1
I think I didn't explain something well. I have in _form.gsp 3 embedded _form.gsp (I said in my question 1 to simplify). So when I edit _form.gsp, the others must be updated too. I want to call the update action of the "child" controllers to update the forms, but not move to them. I want to keep being in the "parent" controller so when everything updates, the show.gsp of the "parent" will appear. Do I explain it better now?
Why don't you redirect or chain with all need params?

ASP.NET MVC flow (how are the models created, populated and passed around)?

I've seen flow charts of the life-cycle but they never seem to answer this question OR I'm just not getting it.
So if user hits a registration page is it:
Routing engine chooses controller.
Controller checks to see which view should be displayed, checks to see if it is strongly typed and if so instantiates the correct model.
Calls the View, passing the empty model in.
I'm also interested in what happens when the form is filled out and submitted.
I'm not looking for anything super technical, just something conceptual...
Regardless of the user actions (followed the link, entered the URL, submitted the form) the basic flow of the MVC application is the following:
According to the routing table Controller's name and method (aka Action) that will handle the request are defined.
If there were any request parameters (values in form for example) they are associated with the Action's parameters.
Request context is generated (contains details about request, client, server, etc.)
Object of Controller's type is created, Action (method) of this object is called with given parameters.
After processing, Action returns an appropriate result, most likely View (could also be Json, plain text, anything).
View is rendered and send back to the client as a response.
Of course, a lot of details are left aside here, but this is the general conception.
Update: some words about models.
Models are used to pass data from the Controller to the View. There are two main approaches:
Using ViewData collection - basically a regular key-value dictionary. In Controller it is filled with data:
ViewData["SomeKey"] = "someValue"; //not only string, any object can be here
return View();
And in View values are retrieved by keys:
<%= ViewData["SomeKey"] %>
Strongly typed Views. A Model class that will contain necessary data is created. View is specified to be strongly typed with this class, and when Action returns a View object, it passes an instance of this class as a parameter. Here is some code example:
Model:
public class SomeModel
{
public string SomeKey { get; set; }
}
Controller:
SomeModel model = new SomeModel();
model.SomeKey = "someValue";
return View(model);
View:
<%# Page ... Inherits="System.Web.Mvc.ViewPage<SomeModel>" %>
...
<%= Model.SomeKey %>

Grails: Unable to get model data from controller to view

I have been using Grails for last 3 weeks (learning and working). I have been working on porting a JSP/Servlet application to Grails and it has been absolute "fun" porting the application.
I have facing an issue and have been searching, reading but could not solve it yet.
In the GSP page I have a textfield and search button where user enters ProductID. I have a controller which is called from jQuery Ajax method when a search button is clicked.
// ----- Part of jQuery Ajax call ---
$.ajax({
type : "post",
url : '/${grailsApplication.metadata['app.name']}/product/checkProductAjax',
data : "pid="+proID,
// ----- Contoller code-----
class ProductController {
def scaffold = true
def checkProductAjax = {
def product= Product.findByProductId(params.pid)
if(product) {
[product: product] // model to get data in GSP page.
render(product.toString() + ":" + product.id)
} else {
render("none")
}
}
}
Ajax call and everything works fine. The problem I am facing is how to get the model (i.e. the Product data back to the GSP page i.e. [product: product] and display in GSP as for e.g. Product Name: ${product}
How can I get it working? I have read examples where it is mentioned that just setting the model [product: product] will help to get the data in GSP.
Product Name: ${product} always shows blank in the GSP page Product Name:
Please tell me what I am doing wrong.
Cheers!
Jay Chandran
[product: product] and render(product.toString() + ":" + product.id) are incompatible. When you see a controller action whose last line is a map like [product: product] this is the implicit return value since it's the last statement of the action closure - it's the equivalent of return [product: product]. But if you have a map in the middle of a method it's just created and discarded. It's pretty much equivalent to
def ignoreThisMap = [product: product]
// other code
Since you're making an Ajax call though, putting the product in the model doesn't make sense since you aren't going to re-render the GSP. You're going to render text, JSON, XML, or some other content that the client-side JavaScript will use to update some subset of the html. So you probably want something closer to
if (product) {
render product as JSON
}
else {
render "none"
}
and then you can use jQuery or Prototype to evaluate the JSON and extract the data in your JavaScript.
you probably want to use the grails tags that are created for this type of work; it wraps the AJAX code all up for you
http://www.grails.org/Ajax

Resources