Best way to render different view for Mobile platform

Topics: Customizing Orchard
Jul 10, 2012 at 8:14 PM

We have a theme that's been formatted for desktop browsers.  What's the best way to approach having a different layout for a mobile version of a page?  Is it to have a different theme per device/useragent?  Or is there a way to have some sort of inheritance where if a mobile version of a .cshtml file exists, it will load it for a browser that responds IsMobileDevice == 1, else it will load the "default" page?  We've done this before with an MVC 2 application, but what's the current best practice?

Should we create a technique where we use a filter and look for filename-mobile.cshtml?

Coordinator
Jul 11, 2012 at 2:22 PM

Best possible solution is to have adaptive layout using css3 (see Bootstrap)

If that doesn't work for you, you can have an implementation of IThemeSelector that picks the theme depending on the user agent (see Theme Picker feature in Vandelay.Industries and http://gallery.orchardproject.net/List/Themes/Orchard.Theme.VuLuMobile)

Inheritance between themes should work if your mobile theme declares its parent in its manifest.

Jul 11, 2012 at 7:14 PM

Thanks Bertrand, yeah, I hyperlinked your blog post in the original post.  I think between Theme Inheritance and Adaptive Layout we should be able to make it work.

Jul 23, 2012 at 10:13 PM

From the look of it, we won't be able to use the adaptive layout idea. And, I'm not 100% sure the theme inheritance idea will work either. 

What we're thinking is we need to have a way to support alternate views (Layout_mobile.cshtml) that effectively override the default view (Layout.cshtml) if:

a) we detect they're on a mobile/tablet browser (which we're thinking of wrapping into a service that we can use via the Onestop.common module)

b) the mobile view actually exists.

The reason we're setting aside the adaptive layout idea is we don't want to send everything to the browser, thus forcing the mobile client with limited bandwidth (or high bandwidth costs) to pull down a lot of information it doesn't need.

We're less concerned about the actual device/user agent and more concerned about whether we're dealing with a mobile phone or a tablet (or neither). 

So, we want to be able to direct the user's request to a specific set of views but make the solution robust enough that it can fall back onto the desktop theme/views if the corresponding file doesn't exist.

For example, let's say we have the following desktop views:

Layout.cshtml

Commerce.cshtml

We create a new mobile version for the commerce view but don't bother with a tablet version or anything mobile for the Layout. The result is this:

Layout.cshtml

Commerce.cshtml

Commerce_mobile.cshtml

If a request comes in for the Commerce page and it's from a mobile browser, we'll route to the Commerce_mobile.cshtml template. Since there's no tablet template, we fall back on the Commerce.cshtml for tablets. 

If a request comes in for the Layout page and it's from a mobile browser, we'll give them the Layout.cshtml view since there is no mobile template that exists.

Does the theme selector idea still apply here? More importantly, can it be used in any theme without issue? We were thinking we'd need to look higher up the chain and potentially add alternate views when the shape table is being built (though the problem is, to support modules that might take advantage of this system, we'd need to be able to do the adds after all the modules have been accounted for when building the shape table).

Let me know what you think or if anyone else has an opinion.

Thanks,

Ken Nakai

Coordinator
Jul 24, 2012 at 12:51 AM

Yes, the theme selector idea still applies and it can be used with any theme.

Jul 25, 2012 at 6:08 AM

Bertrand,

I'm a bit of a newbie with the Orchard infrastructure so bear with me here. Can you tell me, do I have to do anything special to get Orchard to recognize my theme selector? I tried your example here:

http://weblogs.asp.net/bleroy/archive/2011/02/27/dynamically-switching-the-theme-in-orchard.aspx

And created a simplistic MobileThemeSelector just to see it in action. I've tried placing it in the Onestop.Common project and the ACME theme and neither seems to trigger (I'm dropping a breakpoint in the middle of the code and debugging). 

I definitely don't need to register the selector anywhere, I'm assuming, right? Do I need to have it at a certain level in the project file structure (at the root or within a theme's folder)? 

I'm doing something like this (just meant to be an empty shell so I can experiment until I can get it working):

 

namespace Themes.Services
{
	public class MobileThemeSelector : IThemeSelector {
        private readonly ISignals _signals;
        private readonly ICacheManager _cacheManager;
        private readonly IWorkContextAccessor _workContextAccessor;
        private readonly IShapeFactory _shapeFactory;
	

		private ThemeSelectorResult _result;


        
        public ThemeSelectorResult GetTheme(RequestContext context) {
            //if (AdminFilter.IsApplied(context)) return null;
            if (_result != null) return _result;
            // If the user reverted to the default, short-circuit this
            var workContext = _workContextAccessor.GetContext();
            var session = workContext.HttpContext.Session;

            _result = new ThemeSelectorResult {
                Priority = 10,
                ThemeName = "SPYO"
            };
            return _result;
        }


	}//end class
}//end namespace

Is there something else I need to be doing? You'd mentioned in the article you could effectively drop this into a theme's own project and use it there to handle theme switching...I just don't see that happening (though I'm sure it's a rookie mistake since I'm new to all things Orchard).

kn

Jul 25, 2012 at 7:33 PM

Actually, Chad suggested I make it a feature in a module and it started working. 

So, my next question is: is this a realistic way to handle this if we want to be able to support fallbacks?

For example, if I have the following set up:

Layout.cshtml

Layout.mobile.cshtml

Pager.cshtml

And I detect the client is connecting with a mobile browser, I want Orchard to look for the .mobile.cshtml files first. If the file doesn't exist for the specific shape or page, then I want it to fallback and look for the regular .cshtml file. 

Based on what I see, it seems like I *could* do something like that here but that'd mean I would have to keep checking for the existence of the appropriate file every time GetTheme is called. I could potentially cache this of course.

I guess I just want to make sure I'm approaching this properly...

Thanks,

kn

Coordinator
Jul 26, 2012 at 2:11 PM

I have one word for you: alternates. And a link, too: http://docs.orchardproject.net/Documentation/Alternates

Jul 26, 2012 at 7:31 PM

Ah, yes, I stumbled on alternates last night. I think that'll cover that just fine (assuming we don't run into a situation where we need alternates that might interfere but I figure that'll be rare). 

I used a shape provider to set the alternates but it seems that only works on shapes (obviously) like Content and whatnot. Am I able to use that system to specify an alternate for the Layout.cshtml?

 

kn

Coordinator
Jul 27, 2012 at 1:35 PM

Yes: http://weblogs.asp.net/bleroy/archive/2010/12/14/switching-the-layout-in-orchard-cms.aspx The post is a little outdated as Orchard now has the URL alternates feature available out of the box (by the way, this is another piece of code you should look at for an example).

Jul 27, 2012 at 6:00 PM

Very nice. Piotr's suggestion ended up being similar but effectively was about adding a Describe for the Layout in the ShapeProvider I'd created, introducing the alternate there. Would you say doing it via the filter is the better way to do it or no different? Just wondering if there's an advantage/disadvantage for one versus the other...

kn

Coordinator
Jul 28, 2012 at 12:20 PM

I don't think it would make a difference, no. ShapeProvider may be a bit better by being more selective about when it runs, but you'd probably have to test and profile to check that's the case.

Jul 29, 2012 at 11:33 PM

Okay. Thanks for your help Bertrand!

 

kn