Here is a simple description of what i’m trying to do in a mobile application. The end result is supposed to be a page with a list (of athletes) generated dynamically and linking to a page that shows the details of the clicked athlete. That is the part that is working, but the click is slow, so i tried to make fast button out of the button in the list.
Good to know : I use phonegap and test on an android emulator in Eclipse.
I have 2 html pages (in one file, as suggested best practice), the page with the list, and the page with the details
<div data-role="page" id="page_athletes_list" data-theme="a">
<div data-role="header" data-position="fixed">
<h1>My app</h1>
</div>
<div id = "content_athletes_list" data-role="content">
<h2>Athletes Finder</h2>
<ul id="ul_athletes_list" data-role="listview" data-divider-theme="b" data-inset="true">
<li data-role="list-divider" data-role="heading">Name, Firstname</li>
</ul>
</div>
</div>
the details page:
<div data-role="page" id="page_athlete_details" data-theme="a">
<div data-role="header" data-position="fixed">
<h1>My app</h1>
</div>
<div id = "content_athletes_details" data-role="content">
<h2 id = "name_athlete_details"></h2>
<img id = "img_athlete_details" src=""></img>
<div id = "birthday_athlete_details"></div>
</div>
</div>
the javascript i user to create the list dynamically without the fast button. This list needs to be created once on pagecreate.
Note: To change page, hardcoding the page link in the href of the anchor such as href=”#mypage?index=1″ causes problem in phonegap. Once the details is created the first time, it never shows any other data. To bypass this, I put the page link in a data-url attribute, which i retrieve and I use with the JQuery “$.mobile.changePage” function.
/*
function create a list to the detail page with an index parameter.
The index correspond to the the index of an array LIST_OF_ATHLETES where you can find the details information for all the athletes.
This array is used to fill the data in the details page.
*/
$('#page_athletes_list').live('pagecreate',function(){
try {
for (var i = 0; i < LIST_OF_ATHLETES.length; i ++){
var athlete = LIST_OF_ATHLETES[i]; //LIST_OF_ATHLETES is an array that contains all the infos about the athletes.
$("#ul_athletes_list").append("<li data-theme='a'><a id='ul_athletes_list_item_" + i + "' data-url='#page_athlete_details?index=" + i + "' > " + athlete.lastname +", " + athlete.firstname + "</a></li>");
}
}
catch (error) { alert("page_athletes_list : " + error); }
});
//change page on "touchend" event. Use the data-url attribute of the anchor.
$("#content_athletes_list li a").live("touchend", function(){
var dataUrl = $(this).attr("data-url");
changePage(dataUrl);
});
function changePage(dataUrl) {
var page = getParameterByName('#', dataUrl);
$.mobile.changePage(page, {dataUrl: dataUrl});
}
//get a parameter by name from a url (source).
function getParameterByName(name, source) {
if(name == "#"){
var indexStart=source.indexOf('#');
var indexEnd = source.length-indexStart;
var indexParam = source.indexOf("?");
if(indexParam > indexStart){
indexEnd = indexParam-indexStart;
}
return source.substring(indexStart, indexEnd);
}
else{
var match = RegExp('[?&]' + name + '=([^&]*)').exec(source);
return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
}
}
Now i tried many different things to include the google fast button in there but nothing seemed to work.
You can find the code for fast button here : https://github.com/h5bp/mobile-boilerplate/blob/master/js/helper.js
The first thing i tried was to add a new fast button after the creation the anchor.
example :
$("#ul_athletes_list").append("<li data-theme='a'><a id='ul_athletes_list_item_" + i + "' > " + athlete.lastname +", " + athlete.firstname + "</a></li>");
new MBP.fastButton(document.getElementById('ul_athletes_list_item_' + i), function(){changePage("#page_athlete_details?index=" + i )});
When i do this the document.getElementById doesn’t find the anchor ‘ul_athletes_list_item_’ +i.
Probably because it isn’t in the dom yet.
I changed strategy and tried to list element via javascript then create the button the newly created element.
$('#page_athletes_list').live('pagecreate',function(){
try {
for (var i = 0; i < LIST_OF_ATHLETES.length; i ++){
var athlete = LIST_OF_ATHLETES[i];
var page = "#page_athlete_details?index=" + i ;
var list = document.getElementById("ul_athletes_list");
var li = document.createElement("li");
var anchor = document.createElement("a");
anchor.innerHTML = athlete.lastname +", " + athlete.firstname;
new MBP.fastButton(anchor, function(){changePage(page)}); //the fastbutton on the current element of the list
li.appendChild(anchor);
list.appendChild(li);
}
}
catch (error) { alert("page_athletes_list : " + error); }
});
This doesn’t work. All the button redirects to “#page_athlete_details” with the index value equals to the last element of the array LIST_OF_ATHLETES. If I have 6 elements in my array, all the buttons will have redirect to url “#page_athlete_details.index=5”. Instead of having first button with index=0, second button with index=1, etc…
So finally, the question, if anyone knows why this doesn’t work or has an alternate solution, i would be greatful.
MBP.fastButton is asynchronous – the callback function with
changePage(page)doesn’t actually run until after the loop is finished, at which point i is set to 5.To reliably use a callback in a loop, you need a new scope with each iteration. I usually make the loop itself asynchronous by replacing it with a recursive function, but in this case a self executing function in the body of the loop is probably a better fit.
I renamed the variable to clarify which one is being used, but in this case it shouldn’t matter if the same name is used in different scopes.