Reuse Grails Webflow for mobile and desktop site - grails

I have a grails webflow that works fine for my desktop browser app. Now I'd like to reuse the webflow for my mobile site. I'd prefer not to have 2 separate webflows and just change the pages that are used for each state. I tried the following:
viewState{
String view = 'viewState'
boolean isMobile = this.isMobileUser()
if(isMobile){
view = "/flowDir/mobile/viewState"
}
render(view:view)
}
However this isn't working. If the mobile site is accessed first then the desktop will get the mobile pages and vice versa.
Has anyone encountered this problem? I'd really hate to have 2 webflows that do the same exact thing. I'd also hate to hack into Sitemesh. Any ideas or suggestions on how to reuse this flow would be greatly appreciated.

Try putting the mobile view resolution into an after filter so that your web flow executes the same, but you intercept the view being rendered and rename it.
http://adammonsen.com/post/548

I agree with droggo that responsive design is the best solution.
However, as an alternative, you could potentially have all webflow users going to the same view, but within that view itself you could override the g:layout taglib with a taglib of your own that is able to determine whether you're running as a mobile user or not, and hence can apply an appropriate layout.
It's maybe a little heavy handed in this context, but it would give you a solution that would be reusable across your entire app, not just within webflow, and it keeps the mobile-specific code in one place.
So in your webflow:
viewState{
String view = 'viewState'
[snip] The rest of your code goes here
render(view:view)
}
Then your view:
<myapp:applyLayout name="someWebflowLayout">
[snip] Your non-layout GSP code goes here
</myapp:applyLayout>
Then your taglib:
class MyAppTagLib {
static namespace = "myapp"
def applyLayout = { attrs, body ->
boolean mobileUser = false
[snip] some logic to determine if this is a mobile user or not goes here
if (mobileUser) {
attrs.name = "mobileLayout/${attrs.name}"
} else {
attrs.name = "desktopLayout/${attrs.name}"
}
out << g.applyLayout(attrs, body)
}
}
You would then have two layout files called someWebflowLayout - one within /layouts/mobileLayout and one within /layouts/desktopLayout (although I appreciate these might not exactly match your existing structure)
The code in the taglib above is only a rough guide, and it'd need bolstering to deal with the other parameters that g:applyLayout takes.

Related

Dynamic Content of the layout page in Grails

Imagine you layout page of your grails application has some dynamic content that gets update on each page request. When a page is requested, the controller that is requested has nothing to do with the dynamic data provided by the main.gsp page. How should I manage this?
I mean when a page is requested, how do I update the dynamic portion of the layout portion that the page controller is agnostic about? Plus I do not want to put layout dynamic code is every controller.
You might be able create a TagLib for this.
grails create-tag-lib myLayout
Then make your taglib responsible for the remote service calls. You can do pretty much anything in a taglib that you can to in a controller, and you can also call any Grails services you've already created.
class MyLayoutTagLib {
static namespace = "myLayout"
def stockQuoteService
def getStockPrice = { attrs ->
out << stockQuoteService.getLatestPrice(attrs.stockSymbol)
}
}
Then in your gsp
<myLayout:getStockPrice stockSymbol="${user.favoriteStockSymbol}" />
Or however you get the relevant data to make the remote service call.

ASP.Net MVC dynamically switching Views

I have an ASP.Net MVC 4 application where the user can choose a theme or a design of for their hosted one-page site (within this application). At first, I thought to do this with the built-in Areas but due to some application restrictions I've decided not to use that method. The way I thought to do it (which so far works) is to send the user to the index action of the controller, there find out which theme they have chosen and then return the appropriate view. this way I don't have the action name on the url which is nice since the url needs to be simple like: abc.com/cb/websiteID. btw, every theme/design has one view in the folder.
For some reason this method does not sit well with me and I think there should be a better way of doing this. Is there a downfall to this? Is this method a bad practice? is there a better way?
If I've left out a detail, please let me know and I'll do my best to address it.
Do you have a limited set of themes, which your users can choose from?
If so, I would consider to have a layout-per-theme instead, have a single view and dynamically switch layout based on params...
//in your controller
public ActionResult(int id) {
string layoutForThemeName = SomeService.GetThemeForUser(id);
ViewBag.LayoutName = layoutForThemeName
}
// in your view Index.cshtml
#{
Layout = ViewBag.LayoutName;
}
Do not forget that Razor let you inherit one layout from another, so you could event create base layout with script references etc. and layout for every of your themes.

GSP vs. Controller in Grails

I have some experience maintaining Grails apps; now creating a "task management" application as an exercise.
Apparently there is a view dichotomy of Groovy Server Pages versus Controller actions that render a view, as evidenced by this snippet from a URLMappings.groovy example:
static mappings = {
// ..
"/" (view:'/index')
"/login/$action?" (controller: 'login')
"/logout/$action?" (controller: 'logout')
"500" (view:'/error')
}
where user-facing URLs must be mapped to either views (GSPs) or controllers rendering a view, e.g.:
class LoginController {
/**
* Show the login page.
*/
def auth = {
// .. auth logic
String view = 'auth'
String postUrl = "${request.contextPath}${config.apf.filterProcessesUrl}"
render view: view, model: [postUrl: postUrl, rememberMeParameter: config.rememberMe.parameter]
}
}
From a design perspective, how do I choose which method to use? When do I create views with GSPs/taglibs like typical server pages outputting HTML, and when do I map a URL to a controller that renders through a delegate GSP? Can I combine both approaches? Have I oversimplified the options here?
To add to what hvgotcodes said, related to your question, the only time you'd want to map directly to a GSP view is when that view is effectively "static".
By static I mean that it isn't relying on the database or any real calculations for rendering the view. It can still be dynamic in that it relies on tag libraries for dealing with common elements, and things like the "Welcome user" text at the top of pages.
As soon as you want to deal with user-supplied input, looking up database information, manage more complicated URLs, or include calculations, you should be using a controller.
The end goal is that GSPs only contain visual and layout information, as well as the occasional static block of text. But you should always avoid mixing any logic in with the GSP, because it clutters the code and always leads to maintenance headaches later on.
Edit regarding Tag Libraries:
As I wrote below:
Tag libraries are for any logic that is connected to the view, like looping over elements, or toggling the visibility of something. Whenever you are tempted to put code directly into your GSP, it probably should be put in a tag library. Of course, there are always exceptions for one-offs.
So, if you have logic code in your view, that specifically relates to visual or layout content, that should be put in a tag library. A good example is the <sec:ifLoggedIn> tag from Spring Security Core, which can be used to toggle the visibility of an element if the user is logged in. This is much better than writing it manually like so:
<sec:ifLoggedIn>blah blah</sec:ifLoggedIn>
<g:if test="${session.user?.loggedIn}">blah blah</g:if>
Because it makes the purpose clearer (by its title), as well as abstracting the logic away, so if you later need to change the way something works, you only have to change it in one place.
tl;dr:
GSPs - Simplified "static" content
Tags - Reusable dynamic components specifically for visual or layout content
Controllers / GSPs - dynamic content
I don't think it's a dichotomy. GSPs and Controller actions (are intended to) work in tandem, the controller invoking services to load data in preparation for passing that data to the appropriate GSP.
The url mapping stuff is for if you want to break the Grails convention for urls, which is orthogonal to how loading data and displaying data (are supposed) to work.
The only time (IMHO) there is a dichotomy is when developers in a project code functionality inconsistently; i.e. it is certainly possible to give the appearance of a dichotomy.

Grails: mobile version of a controller

I am wondering if you have tried to make a mobile version of a controller?
Right now I am extending GrailsLayoutDecoratorMapper with my custom MobileDecoratorMapper which applies layout.mobile.gsp if the mobile phone is detected and I would like to do something similar for some controllers. My idea is to check in the filter if there existing a mobile version of a controller (for example SomethingControllerMobile or SomethingController.mobile.groovy) and if so redirect to it instead of a default SomethingController.
The reason for that is I would like to avoid a lot of if/else statements inside controller itself to check whether it is mobile, and if so do something differently - i do not want spaghetti code.
Does it makes sense to you and if so have you tried to do something similar and what was your approach? The only thing that comes to my mind is check for files in the filter but it does not look like a proper solution, i think this should be possible to be done on urlmapping level, where on the basis of the url grails decides which controller to invoke
The Spring Mobile plugin allows you to conditionally execute controller code for mobile devices in a fairly elegant fashion
def list = {
def view = "list"
withMobileDevice {
// mobile-specific logic goes here, in this simplistic example we
// just change the view, but you can do anything you like....
view = "mobileList"
}
render(view: view, model: [list: listInstance])
}

Where should the browser types be segregated in an ASP.NET mobile MVC application?

I am building what will primarily be a mobile browser targeted ASP.NET MVC application. Although it will target the desktop as well in a smaller capacity. (I'm fairly new to both MVC and mobile apps.)
I'm wondering what is the best practice for segregating mobile vs. desktop users in an MVC application.
Should the controller be in charge of checking for browser type? Or, should this type of functionality be reserved for the View?
If checked in the view, can & should a masterpage do the checking? Do you know of any good examples online?
Update:
I just discovered an overload of the View method that accepts a string argument specifying the Masterpage to be used.
For example:
public ActionResult Index()
{
if (isMobile())
return View("Index", "Mobile", myObject);
else
return View("Index", myObject);
}
To me this suggests that at least a few people on the Microsoft team expect major distinctions (such as mobile vs. desktop) to be carried out in the controller. (There's a good chance I'm highly confused about this.)
I think the controller must know the plataform, because you can get a lot of views in distint languages, Some view for browsers (mobile) another view in Desktop App, another view can be a web service, and all views can have different needs.
If you have a few views, you can call views with parameters to mark the type of view:
Index(mobile) and Index(Desktop) as it:
Index(string typeOfApp){
//prepare data, do querys, etc
if (typeOfApp=='Mobile'){
redirectoAction('IndexMobile',ds);
//or
return view('IndexMobile',ds)
}
return View('IndexDesktop',ds);
}
IndexMobile(DataSet ds){}
IndexDesktop(DataSet ds){}
You can get a general method for your action() and another action for every type,
Index -> Index4Mobile & Index4Browser & Index4Desktop
And in all of this methods prepare or do something special for every plataform, or a Single Action with multiple views(1 for plataform).
Any code dealing with rendering of your code should exist on the page itself via CSS and javascript. Your controllers should know nothing about how your data will be rendered on screen. The views shouldn't really even know anything about it either - they only expose the data that your CSS will render.
The HTML your View spits out describes your data and how it is organized. Only the CSS should know how to make it look appropriate for whatever device is rendering it.
This link, chock full of javascript should help determine which mobile browser is running.

Resources