Rip's Domain

Pitfalls with jQuery Mobile and how to over come them

Posted in Jquery, jquery mobile by rip747 on April 19, 2012

At work I’ve been tasked with creating a mobile app using jQuery Mobile and Phonegap. Needless to say, I’ve had nothing but issues. Below are some of the pitfalls that I’ve been running into and how to over come them. This post is a work in progress and I will add to it as things come up.

1) When creating additional pages, ONLY include the `data-role=”page”`.

First, let me explain what I mean by data-role=”page”. When you create your index.html for your jQuery Mobile project, you set it up like so:

<!– index.html –>
<!DOCTYPE html>
<html>
<head>
<title>My Project</title>
<meta name=”viewport” content=”width=device-width, initial-scale=1″/>
<link rel=”stylesheet” href=”css/jquery.mobile-1.1.0.min.css” />
<script type=”text/javascript” charset=”utf-8″ src=”js/jquery-1.7.1.min.js”></script>
<script type=”text/javascript” charset=”utf-8″ src=”js/jquery.mobile-1.1.0.min.js”></script>
<script type=”text/javascript” charset=”utf-8″ src=”js/phonegap-1.4.1.js”></script>
</head>
<body>

<div data-role=”page” id=”home”>

<div data-role=”header”>
<h1>Your header</h1>
</div>

<div data-role=”content”>
<p>The content goes here</p>
</div>

<div data-role=”footer”>
<p>The footer goes here</p>
</div>

</div>
</body>
</html>

Notice that we have our opening html tag, our head section with all our stylesheets and javascript includes, our opening body tag, our page div (containing the head, content and footer of the page), our closing body tag and closing html tag. This is standard when creating a html page and something we’re all use to.

Now let’s say you want to create another page called search.html. You would think that you would need to copy the head  section, body and html tags to the search.html page, but THIS IS WRONG! All the search.html page would contain is the page div like so:

<!– search.html –>

<div data-role=”page” id=”search”>

<div data-role=”header”>
<h1>Search</h1>
</div>

<div data-role=”content”>
<p>The form used to search</p>
</div>

<div data-role=”footer”>
<p>The footer goes here</p>
</div>

</div>

The reason for this is that jQuery Mobile will inject the search.html page’s content into the index.html via ajax. Because of this, if you put the html, head, and body tags into your search.html page, they will get duplicated. This can cause all sorts of issues that I won’t even go into. Just remember that you only need the html, head and body tags on the index.html page.

2) Disable ajax caching globally

Supposedly in jQuery Mobile disabled ajax caching of pages in 1.1.0. However, I was still having issue with the pages being cached so this was making development a real pain. Luckily you can disable ajax caching altogether by doing:

<script>
$.ajaxSetup ({
// Disable caching of AJAX responses
cache: false
});
</script>

Just put that in your head section on your index.html page and you should be golden.

3) Multiple events firing

This was a HUGE pain in the ass. You normally see this problem when submitting a form from one page to another. On the calling page, you might have some javascript that is bound to an event (like pageshow) that generates some dynamic content after doing an ajax call. If you look in your Net tab in firebug, you’ll notice that the ajax call will increment with each visit. So on the first visit it fires once, the second visit it fires twice and so on. The reason for this is because, again, of the way jQuery Mobile pulls in pages via ajax. Because it will pull the page in for each visit, it will continually add the code you want to run to the event stack on each visit.

Now I’ve seen people try to solve this by placing the code in the `pageinit` event since that only fires the first time the page in pulled via ajax, but this doesn’t work when you’re having to create dynamic content based on a search string.

The solution is quite simple once you think about it, just put your code on the index.html and delegate using the on() method. so for instance, if you have page with an id of `search` and you want to run an ajax request to get the results, you would do:

$(document).on(‘pageshow’, ‘#search’, function(){
// add code to get the search results via ajax here
});

Personally I would recommend that you put all the javascript code for your app in a js file and include that on your index.html page.

4) When inserting dynamic content into the DOM you must call trigger(‘create’) in order for the framework to apply the styling.

For my app, I have a function that automatically add pagination buttons (previous and next) to the footer. In my template the footer is just defined plainly:

<div data-role=”footer”></div>

In my javascript code, I add the pagination by calling the html() method on the footer object (code is summarized):

var loc = {};
loc.self = $(this);
loc.footer = $(‘[data-role=”footer”]’, loc.self);
loc.footer.html(pagination(loc.params.page, loc.results.PAGES));

The issue was that none of the styling was taking affect on the footer and the prev and next button were showing up as just links. I found in the jQuery Mobile form that you should call page() on the object after altering it, but this really didn’t work. After some more search I found that what I really need to do was call trigger(‘create’) on the object instead. the nice thing is that you can chain this after the html() call and it still works:

loc.footer.html(pagination(loc.params.page, loc.results.PAGES)).trigger(‘create’);

5) When creating a dynamic listview and inserting content into it, you need to call listview() and then listview(‘refresh’) to reapply the styling.

This is basically the same problem as #4 only this time we’re dynamically creating a listview an inserting content into it. In my app, I use Liquid as a templating language as it’s just making life soooo much easier then concatenating javascript strings. So to create my list view, I have it defined in my Liquid template like so:

<script type=”text/liquid” id=”arrestSearchResults-markup”>
{% if RESULTS.size %}
<ul id=”arrestSearchResults-listview” data-role=”listview”>
{% for item in RESULTS %}
<li>
<a href='{{LINK}}&jms_number={{item.JMS_NUMBER}}’ class=’arrestSearch-details’>
<img src='{{item.PHOTO_THUMB}}’ />
<h3>{{item.LAST_NAME}}, {{item.FIRST_NAME}} {{item.MIDDLE_NAME}}</h3>
<p>{{item.JAIL}}</p>
</a>
</li>
{% endfor %}
</ul>
{% else %}
<h3>No records found</h3>
{% endif %}
</script>

The target content div is defined plainly, just like my footer is in #4:

<div data-role=”content”></div>

to compile the template and insert it into the content div, I do the following in my code (code is summarized):

var loc = {};
loc.self = $(this);
loc.markup = $(“#arrestSearchResults-markup”).html();
loc.target = $(‘[data-role=”content”]’, loc.self);

// render the markup to the listview
loc.target.html(Liquid.Template.parse(loc.markup).render(assigns));
// refresh the listview
loc.target.find(‘ul’).listview();
loc.target.find(‘ul’).listview(‘refresh’);

Basically what I’m doing is getting the template markup and the content div and putting them into a variables. I then compile the Liquid template and pass in the assigns object that contains the information to render the template.

The key to all of this is the next two lines which finds the unsorted list (‘ul’) which contains the listview a just injected into the content div and calls listview() on it, this tell jQuery Mobile to treat the ul as a listview object. I then call listview(‘refresh’) to have the framework apply the styling to it.

6) When performing validation on a form, the form will still submit.

Here is the setup. You have a form and you’re trying to perform some sort of validation on it when the form is submitted and show the visitor some errors. You tie your validation to the form’s submit event using submit() and include event.preventDefault() good measure when any error occur. However, the form still submits even though errors are through, the event.preventDefault() does prevent the form from not submitting. Heck, you even throw in `return false` hoping the form won’t submit, but it still does.

The issue is that the form is being submitting via ajax and you can’t stop the ajax submission from happening through standard means. The only thing you can do is turn off ajax and submit the form yourself. Now in older versions of the framework, you could turn off ajax for form submissions separately, however in the latest version (1.1.0) you can only turn off ajax globally by setting `ajaxEnabled` to false. This sucks as you most likely want all the ajax goodness, just not on form submission.

The way around the is to add `data-ajax=”false”` to the form:

<form id=”myform” action=”somepage.html” method=”get” data-ajax=”false”>

The will prevent the form from being submitted via ajax. Now the fun part if how in the world are you going to submit the form data to the action page using ajax so you get that nice ajax spinner thingy when you’ve turn ajax off? The answer is manually submit the form data by serializing it and appending it to form’s action attribute. Then use `$.mobile.changePage()` to submit the data via ajax. Below is a little helper function I wrote to do this:

submitForm = function(formid){
var form = $(“#” + formid);
var page = [];
page.push(form.attr(‘action’));
page.push(form.serialize());
$.mobile.changePage(page.join(‘?’));
}

To use, just call submitForm(‘your form id’) and it will handle the submission for you:

submitForm(“myform”);

7) Calling trigger(‘create’) on date-role=”header” has no effect

Though you need to call trigger(‘create’) on the data-role=”content” when adding dynamic content for it to style properly, this doesn’t hold true for data-role=”header”. The solution is to call trigger(‘pagecreate’) instead.

————————–

I will continue to add to this post as more issues come up. Please let me know if you have any tips in the comments below.

Advertisements

PopUpWindow updates: MIT license and Unload callbacks

Posted in Jquery, Opensource, PopWindow by rip747 on February 14, 2010

It’s been quite sometime since I got to work on PopUpWindow now that CFWheels has taken over my life.

I find it amazing though that I still get emails, requests and contributions from this simple plugin. The biggest request I get is from people wanting to use PopUpWindow in their commercial applications and needing to know what the license is. I’ve always said that all the software I write is open source and you’re free to do with it what you want, however I understand that this doesn’t fly in the corporate world. After looking over and talking about licenses with others who write open source software, I’ve decided to follow others and put PopUpWindow under the MIT license. I think this is the least restrictive license out there and finally clears the air.

PopUpWindow also got an update thanks to Jason Holden who added Unload callbacks. This is what I love about open source, the software that I start gets further redefined by complete strangers who only want to see it improve. It’s totally awesome. Thank you Jason.

jQuery: Quick, cute, double form submission prevention

Posted in Jquery by rip747 on February 3, 2009

$(“form”).each(function()
{
var $that = $(this);
$that.submit(function(){
$that.find(“input[type=’image’],input[type=’submit’]”).attr(“disabled”, “true”);
});
});

what i like about this approach more than anything is that it handles both image button and regular form buttons

Chaining a bind and trigger with jQuery to elminiate functions

Posted in Jquery by rip747 on July 17, 2008

yesterday david shuck posted some jquery code he was using to toggle the display of some form information. one of the things i noticed about his code was that he was using jquery to bind to the change event of a radio button, but the code to acutally toggle the display was contained in a separate function.

i commented him back about how he could combine these two functions into one jquery chain thus making the code a little more readable. today i want to share this with you, let’s take a look at the two functions:

$("#RequireCCInfo").change(function(){
    toggleCreditCardCompanyPanel();
}); 	

function toggleCreditCardCompanyPanel()	{
    if ($("#RequireCCInfo").attr("checked") == true)
    $("#CreditCardCompanyPanel").show();
    else $("#CreditCardCompanyPanel").hide();
}

toggleCreditCardCompanyPanel();

basically the first function bind to the change event of a checkbox with an id of RequireCCInfo and then calls the toggleCreditCardCompanyPanel to toggle the display of the panel.

so how could chaining in jquery help us clean this up a little? remember that with jquery you can bind a function to an event and also trigger event. with this knowledge you can do things like:

$(function(){
$(“#RequireCCInfo”).bind(“change”, function(){
// your code
}).change();
});

as you can see from the code above, we’re binding some code to the change event and then immediately after triggering it, this is the same thing a creating a separate function and then calling it. armed with this knowledge we can now perform the clean up:

$(function(){
$(“#RequireCCInfo”).bind(“change”, function(){
$(“#RequireCCInfo:checked”) ? $(“#CreditCardCompanyPanel”).show() : (“#CreditCardCompanyPanel”).hide();
}).change();
});

BASH IS BACK!!!!! IT’S BASH FRIDAY BITCHES!!!!!!!

Posted in BASH!, Fridays, Jquery by rip747 on February 29, 2008

BASH was really slow there for awhile so I had to let it catch up. Stupid me, it kinda overlapped me so this week is a HUGE BASH posting. Also There is a little something at the end of the list (don’t peek).

Generous Plug: My brother started a blog called My Junk Mail. Basically it’s a collection of all the jokes and funny shit he gets sent to him on a daily basis. Trust me on this, he gets some good stuff. You would never think that people in the mortgage industry on that fucked up…. and to think these pricks are the ones that get us money O_o

http://www.bash.org/?830741
http://www.bash.org/?830747
http://www.bash.org/?830989
http://www.bash.org/?831195
http://www.bash.org/?831285
http://www.bash.org/?831311
http://www.bash.org/?831674
http://www.bash.org/?832266
http://www.bash.org/?832291
http://www.bash.org/?832919
http://www.bash.org/?832984
http://www.bash.org/?833499
http://www.bash.org/?834654
http://www.bash.org/?835030
http://www.bash.org/?835536
http://www.bash.org/?835939
http://www.bash.org/?837574
http://www.bash.org/?839482
http://www.bash.org/?839563
http://www.bash.org/?839694
http://www.bash.org/?839727
http://www.bash.org/?841280
http://www.bash.org/?842161

(your peeking… aren’t you, you fuck!)

I’m starting something new. Every week (hopefully) I’ll be picking out the top two bashes for the week and posting them at the end of the list. These are the ones I think are the best, and on that note, I want people to start leaving comments telling me what their favorite for the week is. During the slow times on bash.org, I can look back and pick out some good ones for my Classic BASH posts.

Don’t let another Friday go by without BASH!!!!!

http://www.bash.org/?833485
http://www.bash.org/?835023

And now for something new:

PopupWindow v2.0.1.1 and version name changes

Posted in Jquery, PopWindow by rip747 on February 20, 2008

This project has now been moved to Github.

PopupWindow v2.0.1 now available

Posted in Jquery, PopWindow by rip747 on February 13, 2008

Quick little thing. I’ve updated PopupWindow to now support the location and menubar attribute as suggested by Matthew. You can download the latest from the box.net sidebar.

Remember to comment here with your suggestions. Thanks

PopupWindow v2.0.0 now available

Posted in Jquery, PopWindow by rip747 on January 22, 2008

This project has now been moved to Github.

Happy Birthday jQuery! Version 1.2.2 released

Posted in Jquery by rip747 on January 15, 2008

Today marks the second birthday for jQuery (my favorite javascript library)! To celebrate, version 1.2.2 has been release. Go check it out!

Tagged with: ,

PopUpWindow is officially a “Most Popular” jQuery plugin. Who’s using it?

Posted in Jquery, PopWindow by rip747 on January 14, 2008

Damn I feel good and shocked right now. Who would have thought that a jQuery plugin I wrote on a whirlwind would get this much attention. I think I literally wrote the first draft within 5 minutes. At the time I was working at revamping a website that used a lot of popupwindows and needed a way to manage the different sizes of the windows. Our the next couple of days I kept adding to it and decided to release it to the public. It’s grown over time to what it is today.

What I would like to know how is who’s using it? Click here to go to the “homepage” for the plugin and leave a comment with a link to your website. Tell me in the comment what your think about it. If anything it will give you a little traffic since the page is getting between 150 -200 visits a day.