after jQuery mobile pageShow silentscroll, page jumps to top - jquery-mobile

We have a basket page, where there are the products, and then the shipping methods. This is a jQuery mobile site.
What I want to achive, that if a shipping method selected, then if there is a page reload, jQuery mobile jumps to a div to the shipping methods.
Here is the code, what scrolls to the shipping methods. This is an inline script.
$(document).on("pageshow", function (e, ui) {
$.mobile.silentScroll($('#kosar').offset().top);
});
Expected result: on page refresh, the window scroll to the #kosar div.
Current result: page scrolls to the #kosar div, but immediatly scroll to the top of the page.
What we discovered, if some error is occures after the silentScroll, the window is not jump back to the top of the page. So it seems, something after the pageshow scrolls it to back, but we do not know, what.
For example:
$(document).on("pageshow", function (e, ui) {
$.mobile.silentScroll($('#kosar').offset().top);
undefined_function(); //This function is not exists
});
Here are the non working, and "working" examples:
Here is a live example. When you refresh the page, you will see for a second the big red text, and immediatly after that you will be taken to the top of the page.
Here is the example with error.
I've tested it in FF Developer Edition. With Chrome, you need to resize your browser to a littlebit smaller, and refresh some times to see the scrollbar how jumping to bottom and up.
How can I prevent this annoying scroll to top?

I think, this is a bug in the jQuery mobile js, I've reported it to them.
Finally I figured it out.
Version:
http://ajax.googleapis.com/ajax/libs/jquerymobile/1.4.5/jquery.mobile.min.js
I've made a breakpoint in the jQuery mobile js silentScroll definition, and what I've see, for some reason it run twice. The first is a good call, ypos is a number, where I want to jump, this is why it jump to the right place.
But, later, at line 15432 here are these lines of codes, what is running on document ready:
// window load event
// hide iOS browser chrome on load if hideUrlBar is true this is as fall back incase we were too early before
if ( $.mobile.hideUrlBar ) {
$window.load( $.mobile.silentScroll );
}
And when it's happens, on the second call, the ypos for silentScroll will be an object, not a number, as the function expects, and if it not a number, then jQuery mobile set the ypos to $.mobile.defaultHomeScroll what is actually 1 if you do not modified. This is why it jumps back to home.
Warning: If you think, you just need to set the $.mobile.hideUrlBar to false, you are wrong. I've tried it, but it had side effects, because in line 15416 there are another reference for this variable, and if you turn off, then when you go from a page to another, you wont be redirected to the top of your second page.
So the solution was to comment out this $window.load( $.mobile.silentScroll ); and now everything is working as I expected.

Related

Disable jQuery Mobile transition when going back in iOS7 Safari history

As described here in Safari on iOS7 - if you swipe in from the left of the screen it triggers a history back event as if the user clicked the back button.
The default behavior of jQuery Mobile is to reverse the transition that was used to reach a particular page when going back to the previous page. This works great when using the < and > buttons but looks terrible when swiping in from the left.
Is there a way to completely disable transitions in the 'reverse' direction using jQuery mobile?
Just capture the pagecontainerbeforetransition event on the page widget.
You can then look at ui.options.reverse and cancel the transition. If you want you can detect iOS7, but I think I'll just give this to all my visitors.
$(document).on("pagecontainerbeforetransition", function (event, ui)
{
if (ui.options.reverse == true)
{
ui.options.transition = "none";
}
});
Here's a sample of a typical ui.options object.
{"reverse":true,"changeHash":false,"fromHashChange":true,"showLoadMsg":true,
"allowSamePageTransition":false,"transition":"none"}
For some reason reverse always seems to be true even when navigating forward. May be a but, but I decided to check for it anyway.

jQuery Mobile Dialog on page load

Working on my first jQuery Mobile app. There is a localStorage value that must have a value throughout the application, so I tapped into the pageshow event to check this value:
$(function () {
$("div[data-role='page']").on("pageshow", function (event, ui) {
if (getValue() == null) {
// show the dialog
$.mobile.changePage("#dialog");
}
});
});
This works when navigating through the various pages, but never gets called when the first page loads. I tried to copy the above If statement again below the part where I add the pageshow listener, but it has the effect of showing the dialog, hiding it, then showing it again.
On that first page, it seems like opening the dialog is triggering pageshow (which is strange, considering my selector), which in turn triggers another dialog. Does anyone have advice on how to get around this, or a better way to go about the whole thing?
UPDATE #1: I tried
$.mobile.changePage( "#mypage", { allowSamePageTransition: true, transition: "none" } );
but it had the same effect as my original problem where it launches the dialog, then hides it, then shows it again. It seems like somehow launching the dialog is firing the pageshow event, even though I tried to filter that out in my selector. Note that if you remove the transition: "none" option, the dialog does not appear at all.
UPDATE #2: I also tried to create a blank initial page, then do a simple page transition
$.mobile.changePage("#mypage");
but it still does not have the correct behavior. In this scenario, it does take me to the next page, but the pageshow event does not fire, because my dialog does not appear. I know it is not firing because I can select another page from my navigation menu and the dialog does appear.
UPDATE #3: I changed my selector where I attach the pageshow listener. Instead of selecting where data-role="page", I am selecting the specific pages by their id. Then I re-tried both of the approaches I described in my previous two updates, but it still works incorrectly. First, when I try to refresh the initial page using allowSamePageTransition, it seems that pageshow fires twice, because the dialog launches twice. Then, when I try using a blank initial page, and then do a redirect immediately after I attach the pageshow listener, nothing happens and the dialog never appears. If I navigate to any other page, the dialog works as expected. I don't understand why this first page is so troublesome.
Set a time interval to show the dialog, rather than call it once the page is shown.
$(document).on('pageshow', '#myPage' ,function () {
if (getValue() == null) {
setTimeout(function () {
$.mobile.changePage('#dialog');
}, 100); // delay above zero
}
});
This way, the dialog will popup on pageshow event and only once.
update
I found this interesting jQueryMobile events diagram on this blog. It explains why a dialog or a popup is fired twice on the first page and not on the rest of the pages in case of multi-pages structure. It seems it fires once the page is ready into DOM and again when on pageshow. Setting a timeout prevents the dialog from firing on pageinit, and therefore skips that event until pageshow is triggered.
Image / diagram source: http://bradbroulik.blogspot.co.nz/2011/12/jquery-mobile-events-diagram.html
Most probably is that on first page, that event is already fired when your piece of code is executed. Which explains why you get nothing only on the first page.
About your second point, it's normal since, changePage will "change" the page to the dialog, and once you close the dialog, it will return to your previous page. Thus, the if is executed 2 times.
My suggestion is that for the first time you enter the first page, you can re-transition to the same page just after you register the callback for the pageshow event.
I used "pagecreate" and that seems to solve my problem (so far...)
$(document).on('pagecreate', "#page-formyID", function () {
//whatever
});

jQuery Mobile popup that doesn't move when scrolling the page

I am using jQuery Mobile 1.3.0 RC1. I have a popup that I create programmatically at the bottom of my page and close after a few seconds using setTimeout (toast notification). It works very well, however if I happen to scroll the page while the popup is displayed, the popup gets scrolled too. I would like the popup not to move, i.e. stay in its position relative to the screen, not relative to the page. Is there a way to do that ?
I have tried playing with the data-position-to attribute in the HTML element, with the positionTo option of the "open" method, and tried placing the popup element inside a fixed transparent footer, none of these resulted in the desired behavior.
I had a similar problem last week. Finally solved it using modal dialog instead of popups.
For popups, I could find following.
$("#myPopup").on({
popupbeforeposition: function () {
$('.ui-popup-screen').off();
}
});
Which helped me in prevention of closing the dialog while user touched outside of popup. But scrolling issue was still there. So I changed all popups to modal dialogs. Hope it helps someone.

UIWebView loading but not displaying content

UIWebView successfully loaded content, but is not displaying it. UIWebView is just white screen. BUT, if you click on this UIWebView it will process your click. For example, if you click at place where the link should be (but in fact the white space), the click processed and next page loaded and displayed OK.
The bug is unstable. I got it only with local HTML file (our homepage, it generated locally), web content loads OK. It happens in 20% cases. But in the same time, it is very sticky. Once got white screen, you can reload this page many times and see white screen (but if you click on invisible link, another page displayed successfully). Sometimes it occasionally appears without any reason. Your can "scroll" this blank screen up and down and it occasionally loaded. This local HTML has a lot of stuff, embedded images, javascripts, etc, and it could be javascript problem, but I can't explain how it can be, that content invisible, but still clickable.
It happens in iPod real device and iPhone simulator 4.3, but can't reproduce it on iPad or iPad simulator.
I spent a whole day trying resolve this. Any ideas?
I solved this!
This really weird behaviour of UIWebView was caused by javascript code. The javascript was like (simplified):
<script>
function onLoad() {
location.href='xxx://pageLoaded';
}
</script>
<body onload='onLoad();'>
The idea of this code was to inform app about the fact that page was loaded. In the app I catch request to xxx://pageLoaded and cancel it (in shouldStartLoadWithRequest). Because request cancellation, I didn't expect any problems here. Espesially, I didn't expect that content will become invisible, but still clicable. I added timer (setTimeout) between onload fires and location.href change. It solves the problem.
NOTE: I know about webViewDidFinishLoad event in UIWebView. This is very simplified example just to explain the problem and the solution. Real javascript is more sophisticated and what it is doing can't be reached by simple use webViewDidFinishLoad.

Lazy Load OpenLayers Map on Dialog Display?

I'm developing a site where the user will choose a point on an OpenLayers map in a dialog box (displayed using jQuery UI) which will then do something on the rest of the page based on the point chosen on the map. The user can also call up the dialog at any time to pick a new point.
I've got the map dialog and passback of lat/long working just fine, but my question comes to page load optimization. I originally had all of my map code right in my $(document).ready() function with my OpenLayers.js call right in the <head> of the page. To try and improve things a bit, I moved the map code into its own .js file and put the links (<script> tags) to both at the very bottom of the <body> tag. It seems slightly better, though I do notice the navigational elements for the map (zoom controls and such) flash briefly on the screen, I presume before the stylesheet tells them to hide. Is there any way I could force the map to only load when the dialog is about to be displayed, as I feel that a slightly delay there would be more ideal than a delay in the main interface loading (subtle as that might be)? And perhaps more importantly, would it make sense to go down that road? To me, it sounds like it would be a slightly better way of doing things, but I'm open to other opinions there as well.
You could both load OpenLayers.js library and create map in dialog's open event. That way the page will load faster and you'll skip loading OpenLayers.js if user never opens dialog.
var scriptAlreadyLoaded = false;
$("#dialog" ).bind("dialogopen", function(event, ui) {
if(!scriptAlreadyLoaded){
$.getScript("/scripts/OpenLayers.js", function() {
//Instantiate OpenLayers map when script is loaded
//...
});
}
else{
//It's second time user opens dialog so script is already loaded
//and map instantiated.
}
});

Resources