jQuery click event not firing in jQueryMobile - jquery-mobile

Using jQuery jquery-1.9.1.js and jQueryMobile 1.3.1 (Chrome 26/Windows 7) I cannot see why one of these 'click' events bound to #one1 fires and the other doesn't:
HTML:
<div data-role="page" id="one" data-theme="a">
<div data-role="header" data-position="inline">
<h1>One</h1>
</div>
<div data-role="content" data-theme="a">
[one]
two
three
</div>
</div>
JavaScript:
<script>
$(document).on( "mobileinit", function() {
$(document).on('click', '#one1', function(e){
console.log('firing');
});
$('#one1').on("click", function() {
console.log('not firing');
});
});
</script>
When I run it in JSFiddle both events fire when not wrapped in the "mobileinit" event:
http://jsfiddle.net/9NRwa/
What am I missing here?

Intro
First thing first, mobileinit event should not be used for event binding. While it CAN be used like that mobileinit was not created for that purpose. It was created for jQuery Mobile parameter auto-initialization, so it should not be used for event binding.
Correct way is to use proper page events like pageinit. For more information about page events take a look at my other answer that covers various jQuery Mobile page events and their difference towards usual jQuery document ready paradigm: jQuery Mobile: document ready vs page events.
Not let me answer this question. Events like click can be bound in a few different ways.
Lets look at examples you have used:
Various ways of event binding with jQuery
First example
$(document).on('click', '#one1', function(e){
console.log('firing');
});
This first example is something new that came to use first with now deprecated method live.
Basically it's an event delegation mechanism that allows you to bind event handlers not just to all existing instances of a given node type, but also to any future instances of a given node type (by "type" I mean a set of DOM nodes matched by a given jQuery selector). What I want to say here is, during the event binding that element don't need to exist in a DOM, basically this method works by binding event handlers to the document itself and then reacting to all the events that bubble up through the DOM. So it doesn't matter if element #one1 exist or not during the event binding. You can create it dynamically later and it will still work.
Second example
$('#one1').on("click", function() {
console.log('not firing');
});
This is on old way of event binding. It requires that event exists in the DOM before event can be bind. In your case you were trying to bind this click event to the element that didn't exist in a DOM at that point in time. It doesn't matter it was loaded after the binding process.
Working example
jsFiddle example: http://jsfiddle.net/Gajotres/QmNsa/
Take a look at this example. There you will see 5 different ways of click event binding in jQuery Mobile:
2 click event are bound in HEAD, before page is initialized into the DOM
2 click events are bound in HEAD in pagebeforeshow event, basically this is also a delegation of binding because event are bound when page is about to be shown and already inside a DOM
1 click event is bound in a BODY after all page content. Because all content is loaded inside a DOM at this point this click event will work.
HTML :
<!DOCTYPE html>
<html>
<head>
<title>jQM Complex Demo</title>
<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; minimum-scale=1.0; user-scalable=no; target-densityDpi=device-dpi"/>
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.css" />
<script src="http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.js"></script>
<script>
$(document).on('click', '#one1', function(e){
// This example will work because it was bind with event delegation process
console.log('Firing 1');
});
$('#one1').on("click", function() {
// This example will not work because event do not exist in this moment
console.log('Not firing');
});
$(document).on( "pagebeforeshow", function() {
// This example will work because it was bind with event delegation process
$(document).on('click', '#one1', function(e){
console.log('Firing 2');
});
// This example will work because element exist in a DOM during the pagebeforeshow event
$('#one1').on("click", function() {
console.log('Firing 3');
});
});
</script>
</head>
<body>
<div data-role="page" id="index">
<div data-theme="b" data-role="header">
<h1>Index page</h1>
</div>
<div data-role="content">
[one]
</div>
</div>
<script>
$('#one1').on("click", function() {
// This example will work because we are binding it when element is already loaded into the DOM
console.log('Firing 4');
});
</script>
</body>
</html>
Conclusion
Do not use mobileinit event for event binding, it will trigger before page is loaded into the DOM and only events bind with delegation will work.
Bind your events in a correct jQuery Mobile page events.
Usefull links regarding this topic:
jQuery Live() Method And Event Bubbling
While live method is deprecated on method should be used instead. In some benchmarks on method is 2x faster.
jQuery Mobile: document ready vs page events
Various jQuery Mobile page events
What does “event bubbling” mean?

As the docs stated:
Because the mobileinit event is triggered immediately, you'll need to
bind your event handler before jQuery Mobile is loaded
Currently, your mobileinit event are running after jQuery Mobile is loaded since jsFiddle will execute your javascript code after finish loaded any libraries you've chosen from the sidebar. To make it works, your structure should look like this:
<script src="jQuery library include first"></script>
<script>
$(document).on("mobileinit", function() {
// Your code here
});
</script>
<script src="jQuery Mobile include last"></script>

Related

JQuery Mobile slider not working

I'm trying to get a slider to work in with JQuery Mobile 1.4.2.
What I would like to do is to use the slidestop event to update a value elsewhere. However, the slidestop event does not fire. I created a test file and tested in Safari and Firefox. Nothing happens when I stop sliding the slider. Could someone please tell me what tutorial I missed?
<html>
<head>
<link rel="stylesheet" type="text/css" href="css/jquery.mobile.css" />
<script src="js/jquery.min.js">
</script>
<script src="js/jquery.mobile.js">
</script>
<title>Concertzender</title>
</head>
<body>
<label for="slider-step">Input slider:</label>
<input type="range" name="slider-step" id="slider-step" value="150" min="0" max="500" step="10" />
</body>
<script>
$( "#slider-step" ).on('slidestop',function( event ) { alert("slidestop event fired"); });
</script>
</html>
EDIT:
I tried the answer suggested below, but I have a slightly more complicated setup than the example above and, therefore, it doesn't work out.
I am trying to avoid the page structure of JQuery Mobile and just use it for the slider. The thing is, when I change to another page, a pagecreate or pageshow is not present, so I cannot wait for those events. What I want is to create a new slider (or rather replace an empty div with another already existing div and then change the id of the formerly empty div's input id. So what I am left with is a unique newly ID'ed input (with corresponding label).
How would I go about and use the slidestop to interact with the new slider? I tried this:
$('newslider').slider();
$('newslider').on('slidestop', function(){alert("slidestop");});
But that gives me two sliders in Safari, of which one does the slidestop and the other is unresponsive. In iOS, however, I get one slider that slides, but does not fire a slidestop event. Omitting the first line gives me an unresponsive slider in Safari and one that doesn't fire in iOS.
So my question is pretty simple: How to enable the slidestop event for a new slider without using JQuery Mobile's pages?
You need to wrap all events/bindings in pagecreate.
$(document).on("pagecreate", function () {
$("#slider-step").on('slidestop', function (event) {
console.log("slidestop event fired");
});
});
Demo

jQuery Tabs 1.9 deprecated "url" - How does one set URLs for tabs?

using jQuery UI 1.9.2 (upgraded from 1.8.23) and I see this on the Upgrade guide;
Deprecated url method and use of title attribute; use aria-controls attribute
(#7132) The url method has been deprecated in favor of leaving the href attribute unmodified even for remote tabs. The href attribute will point to the actual resource and the aria-controls attribute will point to the associated panel. This means that the title attribute will no longer be used to specify a custom panel id.
I have this code:
var $t = $("#tabs");
$t.tabs("url", 0, url);
$t.bind("tabsload", function (event, ui) {
console.log('tabsload fired');
});
$t.tabs("load", 0);
I cannot figure out how to set the url value for the tab (this code is fired when the user clicks on a grid row and the url value is rebuilt based on grid values) now as I do not understand the upgrade guide to use the aria-controls comment.
The approach I have taken is to set the href of the AJAX link and then call the load method to reload the content.
I appreciate that this does not use the aria-controls attribute, but the snippet from the upgrade guide states that this attribute points to the panel - remote tabs receive their content based on anchor contained in the li element, so I figured I should be able to use this approach.
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<link href="Scripts/jquery-ui-1.9.2.custom/css/ui-lightness/jquery-ui-1.9.2.custom.min.css"
rel="stylesheet" type="text/css" />
<script src="Scripts/jquery-1.8.2.min.js" type="text/javascript"></script>
<script src="Scripts/jquery-ui-1.9.2.custom/js/jquery-ui-1.9.2.custom.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function () {
$('#tabs').tabs();
$('#change-button').click(function (event) {
$('#ajax-link').attr('href', 'Handler1.ashx?echo=changed at ' + new Date().toTimeString());
$('#tabs').tabs('load', 0);
event.preventDefault();
});
});
</script>
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div id="tabs">
<ul>
<li>
<a id="ajax-link" href="Handler1.ashx?echo=some text to repeat">Tab 1</a>
</li>
</ul>
</div>
<button id="change-button">Change</button>
</form>
</body>
</html>
I am using a generic HTTP handler (this is the AJAX request) which simply echos back the text it is passed, e.g., Handler1.ashx?echo=some text to repeat. Note that my tabs consist of only one tab that makes an AJAX call to this handler.
To change the Url, I handle the click event of the button and modify the href of ajax-link like this and then reload it:
$('#ajax-link').attr('href', 'Handler1.ashx?echo=changed at '
+ new Date().toTimeString());
$('#tabs').tabs('load', 0);
So for this to work you will need to provide the link you wish to change with an ID and you will need to know at which position the tab page occurs.

Overriding data-ajax="false" from parent container in jquerymobile

I am using the method noted here in the docs to set data-ajax="false" on a parent container for my site but I do have a few cases where I want the page to load via Ajax.
Is there a way to set the default on the parent container but allow individual links to override that setting? Adding data-ajax="true" to the individual links doesn't seem to work.
To set default for full page load:
$(document).on("mobileinit", function(){
$.mobile.ajaxEnabled = false;
});
To set individual, use data-ajax=true.
Somehow other suggestions didn't work for me. But this one did work. Tested.
This script disables all ajax links in the page jquery mobile - and those that should be ajax ones can be used as the a-link below with data-ajax=true.
<head>
<!-- ..... -->
<script src="http://code.jquery.com/jquery-1.8.2.min.js"></script>
<script>
$(document).on("mobileinit", function () {
// Reference: http://jquerymobile.com/demos/1.1.0/docs/api/globalconfig.html
$.extend($.mobile, {
linkBindingEnabled: false,
ajaxEnabled: false
});
});
</script>
<script src="http://code.jquery.com/mobile/1.3.0/jquery.mobile-1.3.0.min.js"></script>
<!-- ..... -->
</head>
<body>
<a href="holysmokewheredidtheajaxgo.html" data-ajax=true>Well, I'm still ajax. That's true!</a>
</body>

How to initialize pages in jquery mobile? pageinit not firing

What's the right way to initialize objects on a jquery mobile page? The events docs say to use "pageInit()" with no examples of that function, but give examples of binding to the "pageinit" method (note case difference). However, I don't see the event firing at all in this simple test page:
<html>
<body>
<script type="text/javascript" charset="utf-8" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
<script type="text/javascript" charset="utf-8" src="http://code.jquery.com/mobile/1.0b3/jquery.mobile-1.0b3.min.js"></script>
<div data-role="page" id="myPage">
test
</div>
<script>
$("#myPage").live('pageinit',function() {
alert("This never happens");
});
</script>
</body>
</html>
What am I missing? I should add that if you change pageinit to another event like pagecreate this code works.
---- UPDATE ----
This bug is marked as "closed" in the JQM issue tracker. Apparently opinions differ about whether this is working properly or not.
It started working when I embedded script within page div:
<body>
<div id="indexPage" data-role="page">
<script type="text/javascript">
$("#indexPage").live('pageinit', function() {
// do something here...
});
</script>
</div>
</body>
Used jQuery Mobile 1.0RC1
.live() is deprecated, suggestion is to use .on() in jQuery 1.7+ :
<script type="text/javascript">
$(document).on('pageinit', '#indexPage', function(){
// code
});
</script>
Check the online doc for more information about .on(): http://api.jquery.com/on/
Turns out this is a bug in 1.0b3 that is fixed in the current head. So if you want a fix now, you gotta grab the latest from git. Or wait for the next release.
jQuery(document).live('pageinit',function(event){
centerHeaderDiv();
updateOrientation();
settingsMenu.init();
menu();
hideMenuPopupOnBodyClick();
})
This is working now. Now all page transitions and all JQM AJAX functionality would work along with your defined javascript functions! Enjoy!
pageinit will not fire in case it is on secondary pages ( NOT MAIN page ) if it is written in common <script> tag...
I have such a problem - on secondary pages that are not loaded with 'rel="external"', the code in the common <script> tag is never executed...
really this code is always executed...
<body>
<div id="indexPage" data-role="page">
<script type="text/javascript">
$("#indexPage").live('pageinit', function() {
// do something here...
});
</script>
</div>
</body>
althrough if you made "tabbed interface", using of "pageshow" is better
I had to put the script in the HTML page section which to me is a bug. It is loaded normally in a browser (not via AJAX) and all on a single page including javascript. We're not supposed to have to use document ready.
The easiest way I found to deal with this was to use JQM + Steal. It works like a charm as long as you put:
<script type='text/javascript' src='../steal/steal.js?mypage'></script>
Inside of the data-role='page' div.
Then use AJAX to connect anything that can use the same mypage.js and use an external link (by using the rel="external" tag) to anything that requires a different steal page.
#Wojciech Bańcer
From the jQuery docs:
As of jQuery 1.7, the .live() method is deprecated. Use .on() to attach event handlers. Users of older versions of jQuery should use .delegate() in preference to .live().
Try this:
$('div.page').live('pageinit', function(e) {
console.log("Event Fired");
});
$(document).on("pageinit", "#myPage", function(event) {
alert("This page was just enhanced by jQuery Mobile!");
});
The events don't fire on the initial page, only on pages you load via Ajax. In the above case you can just:
<script>
$(document).ready(function() {
alert("This happens");
});
</script>

UI Tab load external page, jQueries not working anymore

I've got a problem when i using UI Tabs and load an external page into the tabcontent-DIV. When the page has loaded, all jQueries for this page seems not to work anymore. I read something about callbacks, but it's not clear at all.
Example: I load an external page by ui-tabs, and the loaded content includes a DIV, that should hide automatically as jQueried in index.html
The jQuery click-event is only added to show that a live-event is working.
But i can't get the auto-hide working, after loading the content.
index.html
<script type="text/javascript">
jQuery(document).ready(function() {
// define tabs
$('#tabs').tabs();
// after loading external page, the div "autohideafterload" will automatically hide.
$('#autohideafterload').hide('slow');
$('#autohideafterload').live('click', function() {
$('#autohideafterload').hide('slow');
});
});
</script>
</head>
<body>
<div id="tabs">
<ul>
<li><span>Load data</span></li>
</ul>
</div>
<div id="tabcontent"></div>
</body>
</html>
loadcontent.html
<div id="autohideafterload">This div will hide automatically after loaded this external page.</div>
What am i missing?
Bind your events after the tab's load event is triggered...
$('#tabs')
.bind('tabsload', function(event, ui) {
$('#autohideafterload').hide('slow');
})
.tabs();
You're trying to bind to an element that doesn't (yet) exist. You need to bind after the item loads, and listening to the event is the best way to do this.

Resources