Grails multiple pages form submit - grails

I am using Grails for my project.
There will be a lot of forms across multiple pages and using next and previous to navigate.
Also need to provide the function of save as a draft.
Are there any good way to do this?

Grails provide webflows to make this kind of form wizards. There's also a detailed guide about this in the documentation. Example:
class BookController {
…
def shoppingCartFlow ={
showCart {
on("checkout").to "enterPersonalDetails"
on("continueShopping").to "displayCatalogue"
}
…
displayCatalogue {
redirect(controller: "catalogue", action: "show")
}
displayInvoice()
}
}
Here you have a flow with 3 steps: showCart, displayCatalogue and displayInvoice. You can store objects that will live in the entire flow without beign persisted in the database yet.

Related

Navigate to previous page from grails controller?

Is there a way to navigate previous page from grails Controller and pass model to be rendered, for example I'm having page and want to navigate user/register and to revert to the previous url if there are errors in form?
currently I'm having
def register = {
...
return [user : user]
}
Thanks,
Mika
It looks like you're writing a webflow
Webflows are really the only game in town if you need to manage non-persistent state across multiple pages. Fortunately, webflow provides built-in support for your requirement - going back to the form page if validation fails.

Use controllers globally in Grails

I'm new to Grails and am trying to build a CMS with it.
I want the navigation menu to read from the database so a new page will automatically get a link in the navigation. I've been reading Grails: use controller from index.gsp and related questions, but the answers don't seem to work for me. :(
I've created a domain class named Navigation and a template called _header.
In the "Navigation/list" namespace everything works fine, but outside I can't get to the Navigation data.
I've setup url mapping like so:
class UrlMappings {
static mappings = {
"/$controller/$action?/$id?"{
constraints {
// apply constraints here
}
}
"/"(controller : "Navigation", action : "list")
"/"(view:"/index")
"500"(view:'/error')
}
}
But that doesn't seem to work. Any clues on what could be the problem?
You have two mappings for "/", your new one and the original one: "/"(view:"/index") - for starters you'll need to remove the other one.
Not sure if you are aware of this, but there is an open source CMS built in Grails called Weceem. If you need to use it as part of another Grails application, there is also a grails plug in for Weceem, so you can use it as part of your app.
It might worth looking into it before building a complete new CMS :-)
I was looking at the problem all wrong, urlmapping only made the index.gsp redirect to navigation/list. What I was looking for was the
DomainClass.findAll( String query )
propertie to use in the g:each tag
<g:each in="${Navigation.findAll('from Navigation as n where n.css=?', ['ctBoven'])}" var="oNavigation" status="i">
This allows me to read any database from any page.

Grails webflow - converting action based to web flow

Our app is working using the normal actions in the controller, but there are some difficulties in going backward from one page to another. I've been tasked with converting this to use web flows instead and I'm hitting all kinds of road blocks. Suggestions and insights greatly appreciated.
The controller has actions for list, view, create, sign and print. I've done this:
def index = {
redirect (action: "someFlow")
}
def someFlow = {
init {
// some object settings
}
on("success").to("list")
list {
}
on("create").to "create"
on("view).to "view"
create {
}
on("next").to "sign"
on("cancel).to "list"
view {
}
on("edit").to "create"
on("back").to "list"
sign {
}
on("done").to "list"
on("back").to "create"
edit {
}
on("done").to "view"
}
When I trace through this with the debugger it appears to hit every state in succession without doing anything or stopping on any page. Then it goes back to the list state.
If I click the link for 'create' I get a web page telling me the "resource (/directory path/create) is not available."
But if it could find the list.gsp, why can't it find the create.gsp?
I feel like I'm groping blindly in the dark; none of the books seems to address any of this and I can't find any other resources to indicate why it behaves this way. Anyone have an idea?
Thanks.
The "on" statements need to be inside of the closures. For example, this:
list {
}
on("create").to "create"
on("view").to "view"
should be this:
list {
on("create").to "create"
on("view").to "view"
}
That should at least fix the issue with flying through the whole flow. As for the GSPs not being found, you'll need to create a folder (named "some") in the folder for your controller. Place the GSPs for each of the actions in your flow inside here.
That being said, I agree with Rob that it doesn't really seem like a good candidate for a webflow.

Grails UrlMappings with .html

I'm developing a Grails web application (mainly as a learning exercise). I have previously written some standard Grails apps, but in this case I wanted to try creating a controller that would intercept all requests (including static html) of the form:
test 1
test 2
test 3
test 4
The intent is to do some simple business logic (auditing) each time a user clicks a link. I know I could do this using a Filter (or a range of other methods), however I thought this should work too and wanted to do this using a Grails framework.
I set up the Grail UrlMappings.groovy file to map all URLs of that form (/$myPathParam?) to a single controller:
class UrlMappings {
static mappings = {
"/$controller/$action?/$id?"{
constraints {
}
}
"/$path?" (controller: 'auditRecord', action: 'showPage')
"500"(view:'/error')
}
}
In that controller (in the appropriate "showPage" action) I've been printing out the path information, for example:
def showPage = {
println "params.path = " + params.path
...
render(view: resultingView)
}
The results of the println in the showPage action for each of my four links are
testJsp.jsp
testGsp.gsp
testHtm.htm
testHtml
Why is the last one "testHtml", not "testHtml.html"?
In a previous (Stack Overflow query) Olexandr encountered this issue and was advised to simply concatenate the value of request.format - which, indeed, does return "html". However request.format also returns "html" for all four links.
I'm interested in gaining an understanding of what Grails is doing and why. Is there some way to configure Grails so the params.path variable in the controller shows "testHtml.html" rather than stripping off the "html" extension? It doesn't seem to remove the extension for any other file type (including .htm). Is there a good reason it's doing this? I know that it is a bit unusual to use a controller for static html, but still would like to understand what's going on.
This is related to content negotiation, which you can read about in section 6.8 of the Grails user guide. If Grails recognises the extension as a particular type, the extension is removed from the URL and the type is added to the "format" parameter.
You can disable this behaviour by adding this entry to grails-app/conf/Config.groovy:
grails.mime.file.extensions = false

Administration Area in Asp.Net MVC

My question may be obvious but I'd like to build a well-designed web application.
As for any administration area, the admin should be able to list/create/delete/modify users, articles, posts, etc...
I'd like to know what is the best way to design the application.
Should I create a controller for each one of those items (/Users/Create/id or /Posts/Delete/id), or create all of the action in my Administration Controller (/Administration/CreateUser/id or /Administration/DeletePost/id) ?
You should write a separate controller for each entity to keep a clean separation of concerns for your controller classes. If you only have one controller, then you will only have one Views directory with dozens of views, and your controller will contain dozens of methods, and that will soon become unmanageable.
The answer depends on how much functionality will be in the controllers. Just start of with one controller and if it gets too much split it into a few.
The great thing about MVC is where you put things in your controllers doesn't have to have any effect on the URLs. you can very easily map /Users/Create to e.g. UserAdminController class.
I would just build a new MVC website that handles the administration.
You have a more flexible solution as long as you've separated the data and the business logic in different assembly's. You could then publish your website to a subdomain, admin.yoursite.com for example. That way you don't have to mess with your routes and you can keep them in separate views which imho is the most elegant solution.
Pro's and Con's would be nice to hear.
I'm working on a project which will need the same administration site but haven't got that far yet so this question interests me a lot.
I'm currently using ASP.NET for a large client.
The approach I've adopted is to put the functionality of the action into another class.
Example
I am writing an administration section also. There will be one Administration controller (our admin section is small, if it was larger I would change the routing to allow more controllers, for now we are using the out of the box configuration). If I create an "EditUser" view. I will also create an "EditUserAction" class. All EditUser code will go into the class. I construct the EditUserAction class in the Administration controller class in the Edit User method. This removes all the action specific code out of the Controller class. This way all the action specific code is either in the action method or in the action class. Otherwise, the controller would quickly become overrun with code from various actions. The controller class would balloon to an unmanageable mess in short order.
Class examples
public class Administration: Controller
{
public ActionResult EditUser(string userId)
{
EditUserAction action = new EditUserAction();
}
}
public class EditUserAction
{
public void Save(User user)
{
//save code here
}
}
I hope this explanation is clear. If it's not let me know and I'll clarify.
To answer your question I am doing it the latter(/Administration/CreateUser/id or /Administration/DeletePost/id).
You could use DynamicData for this. It isn't MVC but it can be used together with it and it is really easy to setup and use.
Here is another way of asking my question.
A part of my Master Page:
<% if (!String.Equals(ViewContext.RequestContext.RouteData.GetRequiredString("controller"), "Administration")) { %>
<div>
<!-- Some Code -->
</div> <% } %>
As you can see, in my master page, I'd like to display some part of the page, depending on the user working on the administration area or not.
It works pretty well with only the Administration Controller (/Administration/CreateUser/id)... but it becomes a big mess when I use different controller as User or Article (/User/DeleteUser/id or /Article/Details/id).
I'd prefer to use one controller per entity, but I can't find a way to bond this approach with multiple controllers.
I suggest to use this solution.
But I changed definition to this:
public ThemedViewEngine()
{
base.MasterLocationFormats = new string[] {
"~/Views/{1}/{0}.master",
"~/Views/Shared/{0}.master",
"~/Themes/{2}/Views/{1}/{0}.master",
"~/Themes/{2}/Views/Shared/{0}.master",
"~/Themes/Default/Views/{1}/{0}.master",
"~/Themes/Default/Views/Shared/{0}.master"
};
base.ViewLocationFormats = new string[] {
"~/Views/{1}/{0}.aspx",
"~/Views/{1}/{0}.ascx",
"~/Views/Shared/{0}.aspx",
"~/Views/Shared/{0}.ascx",
"~/Themes/{2}/Views/{1}/{0}.aspx",
"~/Themes/{2}/Views/{1}/{0}.ascx",
"~/Themes/{2}/Views/Shared/{0}.aspx",
"~/Themes/{2}/Views/Shared/{0}.ascx",
"~/Themes/Default/Views/{1}/{0}.aspx",
"~/Themes/Default/Views/{1}/{0}.ascx",
"~/Themes/Default/Views/Shared/{0}.aspx",
"~/Themes/Default/Views/Shared/{0}.ascx"
};
base.PartialViewLocationFormats = new string[] {
"~/Views/{1}/{0}.aspx",
"~/Views/{1}/{0}.ascx",
"~/Views/Shared/{0}.aspx",
"~/Views/Shared/{0}.ascx",
"~/Themes/{2}/Views/{1}/{0}.aspx",
"~/Themes/{2}/Views/{1}/{0}.ascx",
"~/Themes/{2}/Views/Shared/{0}.aspx",
"~/Themes/{2}/Views/Shared/{0}.ascx",
"~/Themes/Default/Views/{1}/{0}.aspx",
"~/Themes/Default/Views/{1}/{0}.ascx",
"~/Themes/Default/Views/Shared/{0}.aspx",
"~/Themes/Default/Views/Shared/{0}.ascx"
};
}
Default theme is default so it is required to exists.
Structure of directory will be:
Content
Themes
Default
Content
Views
Home
Blog
Whatever should be skinned
OtherTheme
Content
Views
Home
Blog
Whatever should be skinned
Views
Articles
Posts
Users
Settings
Other Administration stuff
It depends on the scale size of your admin area,
I suggest you consider to do the following (or maybe document it a bit)
Consider how many entities you want to manage independently,
Consider how many actions each one will have,
Check that is there any dependency between your application and admin area (user access, for user friendly URLs )
then you can specify which approach can help you, Having one admin controller, admin actions in entity controllers, or defining a new Admin project in case of large functional applications.
*If the project scale is growing fast and soon it needs large scale, I would choose third one - having a new admin mvc project.
I hope it help you decide.

Resources