Posts Tagged 'mobile jQuery'

ASP.NET Web Forms and jQuery Mobile Reconsidered

I’ve written before on this blog about the problems with combining Web Forms and jQuery Mobile. At bottom, it boils down to this: the Ajax navigation does not play well with ScriptManager. Beyond that, when working with jQuery Mobile you have multiple pages in the DOM at the same time, so you have to make sure you client-side IDs are unique across the site. And not only does every ASP.NET control already have a client ID, you also have to add IDs to the data-role page elements so that pageinit works properly.

I like the animated transitions – but not enough to make it worth that amount of effort. So I want to stop jQuery Mobile from converting my links and forms to use Ajax. Fortunately, that’s entirely doable.

jQuery Mobile exposes an ajaxEnabled property. If you set it to false inside the mobileinit event, your links will all behave as nature intended.

The one twist is that you need to do this between the script references for jQuery and jQuery Mobile. I placed the above code inside jquery.configuration.js, and then put them together thus:

When I click on the link to test2.html, the request does NOT use Ajax:

Test2.html does NOT have the configuration file:

And as a result, the request for test.html DOES use Ajax:

So – now we can use jQuery Mobile with ASP.NET Web Forms without worrying about all those pesky ID problems… And since that will eliminate most of the problems that arise from combining jQuery Mobile with the ScriptManager, wouldn’t it be nice if we could start using the ScriptManager with jQuery Mobile?

We could just add the configuration and jQuery Mobile scripts after the ScriptManager: but then other scripts might be injected in between, and that might lead to unexpected side effects down the line. So the best case scenario would be if we could inject our configuration file and jQuery Mobile into the ScriptManager itself. Fortunately, we can.

So how do we do that? Well, first we need to create a static class and a static method that calls ScriptManager.ScriptResourceMapping and adds a new definition:

Now the one final step is to tell ASP.NET about our new definitions. For this, we use the System.Web.PreApplicationStartMethod attribute, which runs at a very early stage in the application life cycle:

The best place to add this is inside AssemblyInfo under project properties

Now we can add both our configuration file and jQuery Mobile as ScriptReferences, using the names we specified when we added the definition:

And the end result is that the Web Forms application now uses jQuery Mobile AND ScriptManager seamlessly – with the minor sacrifice of forgoing the fancy animated transitions.

Kevin Rattan

For other related information, check out these courses from Learning Tree:

Building ASP.NET Web Applications: Hands-On

jQuery: A Comprehensive Hands-On Introduction

Allowing Users to Select Mobile or Desktop Views

My jQuery Mobile/ASP.NET MVC site, cocktailsrus.com, began as a pure jQuery Mobile site. I then added a desktop view and automatically switched users to the appropriate view depending on their device. This works pretty well – especially with the 51Degrees NuGet to improve on the built-in device detection – but even so, there are occasions when the automated detection fails. Someone with a new device comes to the site, the device isn’t recognized, and the user ends up with the wrong version.

This bugs me.

Or, to be more accurate – what bugs me is that there’s no way for the user to change to the appropriate view.

That’s is the problem with automatic device detection: it’s fine until it doesn’t work. Then you’re stuck. So the answer, obviously, is to provide the user with a means to override the default device detection. They need a button that lets them switch to the other view.

The problem is – how to override the detection and automatic version selection, especially since I am relying on a 3rd party tool to do the detection for me? Fortunately, there is a solution in the form of another NuGet: jQuery Mobile MVC. Scott Hanselman blogs about it here. It’s an excellent solution to the problem… but the sample view user control provided in the NuGet needs a little tweaking if it’s going to solve the specific problem I outlined above.

First, let’s take a look at the NuGet and what it does for us. So let’s install it:

If you don’t already have a mobile specific .layout file, then the install gives you a basic version with associated CSS etc. designed for mobile devices:

And right at the top of the mobile view is the output (“Displaying mobile view Desktop View”) from a view user control, _ViewSwitcher. This control is really what the NuGet is all about.

Clicking on the link leads the user off to a small controller, ViewSwitcherController, with the single method SwitchView:

So… if you are in a mobile device, you get a choice between the mobile and the desktop view. When you click on the link, it sets the BrowserOverride and the user is given the view of their choice rather than the default. Nice.

It’s very neatly done… except that it doesn’t actually solve the problem I started out with. My problem was – what to do about a mobile device that wasn’t picked up as a mobile device… and this code wouldn’t solve that problem.   It will only display the choice of view to devices that the system already thinks are mobile devices. A mobile device that isn’t detected won’t get any option to switch to a mobile view – even if the _ViewSwitcher control is added to the desktop version. The problem is in the first if statement:

Only recognized mobile devices get the links. I want a user with an unrecognized mobile device to be able to select the mobile view. So in my version, I remove the outer if statement and also some of the ancillary text so that I can use the links as part of the menus. Also, because both versions of the site make extensive use of Ajax, I explicitly redirect the user to the home page when they switch view (otherwise, they might end up getting a partial page):

With this small tweak, I now have links in both the mobile and the desktop versions that seamlessly allow the user to override the default selection and switch between the different views:

Now I just need to do something about that bottom menu, as it’s getting too bulky. Time to upgrade to jQuery Mobile 3 and put the navigation in a panel. Onwards….

Kevin Rattan

For other related information, check out this course from Learning Tree:

Building Web Applications with ASP.NET MVC

New ASP.NET Training Course at Learning Tree

I was back in Learning Tree’s Reston offices last week, presenting the beta of my new ASP.NET course – Building ASP.NET Web Applications: Hands-On.  (The beta is part of our course development process where we try out the course in front of students for the first time.  Their feedback is an important part of refining exercises and slides to make sure that everything is clear, that all the exercises work as written and that we have the right balance of material).

I’ve been busy writing the course over the past few months, which is why this blog went very quiet for a while. The new course takes you all the way from explaining What is ASP.NET? through to building a multi-layer application using Code-First Entity Framework, the Web API and the HTML5 Geolocation API. (I put the course example online, so if you want to see what we build during the week, check out www.learningtreatz.com).

What’s so exciting about the new course? (Apart from the fact that I wrote it, of course…)

Well… there’s Visual Studio 2012….

A lot of people aren’t keen on the new monochrome look and – horrors – capitalized MENU items – but there are some really nice new features like Page Inspector and the new improved Add Reference dialog. Beyond that, it remains a very powerful development environment that makes web development a pleasure. And it means, of course, that we can develop with .NET 4.5 – and that means access to a host of cool new features. There’s the Web API:

And bundling & minimizing – which both reduces the size of your .css and .js files for production and makes sure that all your small files are combined into a single  large file, which is a big help in reducing download times for the client:

And there’s also out-of-the-box support for HTML5…

The class covers all these and more, and takes attendees from creating a simple Web Form at the beginning of the class right through to building a layered application with a Code-First Entity Framework data access layer, a business layer calling IQueryables in the data access layer and a UI that uses everything from combining Model Binding with the ListView through to providing an alternative jQuery Mobile view of the entire web site. So if you’re new to ASP.NET Web Forms or just want to refresh your skillset, why not give it a try!

This is me in full flow at the front of the class…

And helping an attendee with one of the exercises…

Kevin Rattan

For other related information, check out this course from Learning Tree:

Building ASP.NET Web Applications: Hands-On

Combining jQuery Mobile with ASP.NET Web Forms

I’ve written quite a few articles on this blog about combining ASP.NET MVC and jQuery Mobile, but recently I had occasion to combine JQM with ASP.NET Web Forms. Not surprisingly, there turn out to be at least as many compatibility issues with Web Forms as there are with MVC – and since they’re different from the MVC problems I’ve already blogged about, I thought I might as well share them with you here.

The first problem isn’t really a Web Forms issue – it’s all about the fact that the default template created by Visual Studio includes a ScriptManager.

Now, the ScriptManager is a useful control. It’s not just about Ajax. It can be used to ensure that you have scripts when you need them and don’t end up with duplicate copies of the same script resources – ensuring, for example, that jQuery is only added to the page once, no matter how many  validators you add.

However, the ScriptManager has one big drawback from the point of view of JQM: you have to put it inside the HTML form. Here’s what happens if you don’t:

screen grab of error

So the ScriptManager goes inside the form, and the form, of course, needs to be inside the data-role=”page” element. Otherwise, the action attribute wouldn’t be set correctly when you navigate to a new page.  So the obvious thing to do is leave it alone and add the appropriate <div> elements and  data-roles for jQuery Mobile.  And at first it looks like it’s going to work:

jQuery Mobile screen grab

Unfortunately, appearances are deceptive. The ScriptManager acts as a placeholder for the scripts it adds to the page – so the scripts are being added inside the data-role=”page” element. And JQM replaces the content of the page element using Ajax – over and over again. The result is that pretty soon you are disappearing into recursive hell.

The following requests all followed  a single click on the home link:

Many calls to the home page

So – the ScriptManager has to go altogether. That’s fine. We can put the necessary script references in the head and everything works.

Unless we add validators to the page.

The problem is that in the absence of the ScriptManager to prevent duplication, the validators add jQuery to the page irrespective of whether it’s already there – and that reappearance of jQuery AFTER jQuery Mobile breaks JQM. So the next step to running JQM successfully with Web Forms is turning off client side validation.  Or maybe it’s time to give up on the traditional validators and use a version of my data annotation validator from an earlier post….

Kevin Rattan

For other related information, check out these courses from Learning Tree:

jQuery: A Comprehensive Hands-On Introduction

Building ASP.NET Web Applications: Hands-On

Managing jQuery Mobile and ASP.NET MVC Compatibility Issues

jQuery Mobile is a great technology for producing mobile-friendly applications that work on multiple devices.

ASP.NET MVC is a great technology for creating elegant, scalable Web applications.

The two were made for each other: so much so that the Visual Studio 11 beta includes jQuery Mobile along with ASP.NET MVC and even provides a specific mobile template.

Sadly, however, jQuery Mobile and ASP.NET MVC don’t always play nicely together.

I was reminded of this forcefully last night when I uploaded the latest version of my personal website, Cocktails-R-Us (which I’ve now upgraded to ASP.NET MVC 4). The problems tend come down to two things: IDs and AJAX–and sometimes both together.

One issue that bit me this time around was an incompatibility between jQuery Mobile and the ASP.NET authentication framework. I tested the new version locally and everything worked. Everything seemed fine on the live server as well, until I tried to log in using a mobile browser and this happened:

screen grab of error

The problem was a simple one. JQuery Mobile uses AJAX navigation unless you tell it otherwise. The ASP.NET authentication system issues 302 redirects which are no problem to normal requests, but cause issues with AJAX. So the answer is to turn off AJAX. For that, all you have to do is add the attribute data-ajax=”false” to the <a> tag – which means doing the following in ASP.NET MVC:

code sample

A related problem with mixing jQuery Mobile and ASP.NET MVC is the very different assumptions each makes about how you will use the ID attribute.

One of the best things about jQuery Mobile is the elegant, animated page transitions. And one of the worst things about jQuery Mobile is the price you have to pay for them. The animated page transitions work by adding the new page into the existing DOM. That means that while only one page is visible at a time, the content of multiple pages is in the DOM simultaneously.

Now, it’s not as bad as it sounds. JQuery Mobile is not putting the entire page into the DOM – just the part you’ve identified as the content of the page. But it still leads to problems with IDs.

Let’s imagine that a user is going through a sequence of HTML forms that map to ASP.NET MVC controller methods. In those methods, the HTML form is automatically translated into an Entity. And let us assume that each of these entities has a Name property (in my case, for example, Cocktails, Beverages and Ingredients might have the Names ‘Old Cuban‘, ‘Rum’, ‘Mint’). The HTML forms would contain id=”Name” for each of these textboxes. Those IDs would work with validation (as we don’t have repeating forms on the same page) and everything would be fine. Except that with jQuery Mobile’s default behavior, the forms would all exist inside the current DOM, and we would end up with multiple repeating IDs and badly formed HTML.

A jQuery Mobile purist would no doubt say – well, just don’t use the IDs: you could manage without them on the client. Well, yes you could – but that would involve doing a lot of work on the server to reproduce behaviors that are given to you ‘out of the box’ with the MVC framework. The alternative is to turn off the nice AJAX transitions for pages with HTML forms. Unless, of course, you prefer to write your own Model Binder and/or View Engine for ASP.NET MVC to get around the problem.

Personally, I think I’ll just turn off the AJAX.

Kevin Rattan

For related information, check out these courses from Learning Tree:

jQuery: A Comprehensive Hands-On Introduction

Building Web Applications with ASP.NET MVC

Validation Issues with jQuery Mobile and ASP.NET MVC

I’ve written before about the peculiarities of ASP.NET MVC validation. It’s a great technology 90% of the time, but can cause issues if you do something a little out of the ordinary. I came across another one of these unusual circumstances recently when I was testing my development version of CocktailsRUs.

I was running through the site checking that upgrading to the latest version of jQuery Mobile hadn’t broken anything when I noticed something interesting – on one page, the validation ran but nothing visual happened to show that it had done so. The validation worked – the page did not submit – but there was nothing to tell the user what had happened.

It turned out there were two issues. One was a twist on the ASP.NET MVC validation issues I mentioned in that earlier post. The other was specific to jQuery Mobile.

The ASP.NET MVC validation issue

Here is a screenshot of the jQuery Mobile page AFTER the validation has run. As you can see – it is not very helpful:

screen shot of no visible validation

So I took a look at the same functionality in the normal Web view, and the result is a little different – but still not what it is supposed to be:

screenshot of partially visible validation

So I had two problems, not one: the highlighting wasn’t working in the mobile version, and the message wasn’t working in either. Time to do a little digging….

Here is the code inside the .cshtml page:

HTML and MVC code sample

The element and the validation attributes have been hard-coded to get around ASP.NET MVC’s problems with validation and repeating forms. Those problems stem from the fact that ASP.NET MVC uses IDs instead of name attributes to hook up validation. This time, however, the problem is that when it comes to displaying the result of the validation, it DOES use name attributes – and you’ll notice that in the code sample above, the “name” does not match the (case-sensitive) “Name” model property in the ValidationMessageFor() method.

So I changed the name attribute value to match the model property…

corrected code sample

And now we have a validation message:

screenshot of visible label

But it’s still not quite right – unlike the Web view, where both highlighting and text are visible:

screenshot of complete validation

The ASP.NET MVC validation and jQuery Mobile search inputs issue

So what’s going on with the search element in jQuery Mobile? We have a working label, but the input itself doesn’t have the usual CSS look and feel to highlight the error. In this case, the problem lies in the way that jQuery Mobile creates the search box.

It turns out that that the “search” input is being converted to a text input, given a wrapping div and (unsurprisingly) all sorts of CSS decoration.

generated html

The upshot is that the standard MVC CSS validation classes can’t compete and are overridden.

So how to fix it? By tweaking the CSS to make the ASP.NET MVC CSS classes more powerful. In this case, I am only using the search type with a very small number of IDs – so I added CSS rules specific to those IDS…

amended CSS

And the problem went away:

completed validation

So – back to coding… until the next interesting little niggle comes along.

Kevin Rattan

For other related information, check out these courses from Learning Tree:

jQuery: A Comprehensive Hands-On Introduction

Building Web Applications with ASP.NET MVC

Improving Performance with Output Caching

I’ve been spending most of my spare time over the past few weeks refactoring the code for my site, cocktailsrus.com, in the Visual Studio 11 beta–partly to play with the new stuff, but mostly just to replace my original quick-and dirty back end with something more elegant. With the process pretty much complete, the new version of the site will be much more maintainable, as well as more performant and scalable. And I don’t know about you, but whenever I see those two words together, the first thing that leaps to my mind is “caching.”

Caching is a fantastic way of reducing the amount of data access on a website. Unfortunately, it can also be a fantastic way of tying yourself in knots and serving the wrong data to the wrong user. It is just too easy to serve stale data–especially when you transition from a single server to a web farm. So which type of caching to use, and how to avoid serving stale data?

ASP.NET offers two types of caching:  data caching and output caching. Data caching is managed programmatically. Output caching is managed via attributes (MVC) or page directives (Web forms).

Historically, I’ve preferred data caching. I’ve specialized in content management systems over the years, and it’s a very rare situation where a CMS delivers the same content to everyone. Data caching allows very fine-grained control. Unfortunately, it doesn’t play very well with Web farms–at least, not since Microsoft removed some of the core SQL Server technologies that allowed it to do so.

So, given that I want to be able to scale up to a Web farm, the question I asked myself was, Could output caching help my application?

The obvious candidate for output caching is the page that displays individual cocktails. These don’t change very often, and are amongst the most heavily trafficked on the site. Also, and most significantly, retrieving a cocktail from the database involves a complex SQL query with many table joins. (A cocktail has multiple ingredients, related cocktails, an author, etc.) The fewer such calls I make, the better.

On the face of it, caching the individual cocktails should be easy. Each one has a unique ID, so you should need to do is add an OutputCache directive, like this:

output cache directive

Looks easy, doesn’t it? Each time the method is called, the individual cocktail will be cached by its ID for 60 seconds.

Unfortunately, it really isn’t as simple as that. This caching will work–but it will deliver the same version of the output to everyone: mobile device users, AJAX users, non-AJAX users…. You get the picture. A user with JavaScript enabled will suddenly find that they are getting the full page rather than an AJAX payload, leading to pages within pages, like this:

page within page screengrab

So simple caching won’t do. We’re going to need to cache four different versions for each cocktail, specifically:

  1. Mobile with no AJAX
  2. Mobile with AJAX
  3. Standard with no AJAX
  4. Standard with AJAX

Unfortunately, there isn’t a querystring parameter that’s going to allow us to make that distinction, so it’s time for a custom parameter.

The first thing we have to do is override the GetVaryByCustomString() method in the global.asax. Here, we can use the request to filter our caching into the four different groups. The site uses jQuery, and jQuery AJAX requests use the “X-Requested-With” header, so we can use that to determine if this was an AJAX request. That’s half of the problem solved. We can then use the underlying infrastructure (or, perhaps, our own version of it) to find out if this request came from a mobile device.

GetVaryByCustomString code

We then assign this to the controller method and we should have something that caches multiple versions and returns the appropriate version from the cache:

VaryByCustom argument

Which is great… except that when we look at it in Firefox, we have the same old problem:

second page within page screengrab

The issue here is where the caching is happening. Output cache is a clever beast, and it’s automatically offloading the work to the client–which is a great idea, but means that if our client switches from AJAX to non-AJAX versions, we end up delivering the wrong item from cache.

Fortunately, there is a simple solution. The OutputCache attribute accepts a Location argument, which you can use to tell it to cache on the server rather than the client:

Corrected OutputCache attribute

So now I have a caching system that will work happily on a Web farm, significantly reduce data access and provide the appropriate custom view to the client.

Kevin Rattan

For related information, check out these courses from Learning Tree:

Building Web Applications with ASP.NET MVC

Building Web Applications with ASP.NET and AJAX

jQuery: A Comprehensive Hands-On Introduction


Learning Tree International

.NET & Visual Studio Courses

Learning Tree offers over 210 IT training and Management courses, including a full curriculum of .NET training courses.

Free White Papers

Questions on current IT or Management topics? Access our Complete Online Resource Library of over 65 White Papers, Articles and Podcasts

Enter your email address to subscribe to this blog and receive notifications of new posts by e-mail.

Join 29 other followers

Follow Learning Tree on Twitter

Archives

Do you need a customized .NET training solution delivered at your facility?

Last year Learning Tree held nearly 2,500 on-site training events worldwide. To find out more about hosting one at your location, click here for a free consultation.
Live, online training

%d bloggers like this: