Bootstrap Carousel Next/Prev controls stop responding when page is reloaded - ruby-on-rails

I'm using the Bootstrap Carousel feature. On initial load of the page the Carousel next/prev controls work perfectly however when I simpy reload the page these controls no longer respond to clicks even though the interval for "auto" rotating the slides that I've configured continues to work.
I've done alot of research trying to troubleshoot this problems..including reviewing probably 30+ stackoverflow postings on Bootstrap Carousel but none of them offered any solutions for me. After two days of researching this problem I'm still stumped.
Environment/setup:
My browser is Chrome
Libraries included in the following order: a)jQuery 2.1.3, b)Bootstrap CSS 3.3.5, c)Bootsrap JS 3.3.5
Running in Ruby on Rails 4.2 environment
My solution is a pure bootstrap solution (e.g., no special JS other than including variants of $('#carousel-generic-example).carousel() type statement per examples I've seen online..apparently no change in behavior with or without this statement).
I'm a bit puzzled as to why it works properly on initial load but not on subsequent reloads. Perhaps something isn't being loaded properly when I do a re-load of the web page??? Maybe there is some behavior within Rails that is causing this behavior?
If anyone has any theories as to what might be causing this behavior I'd love to hear it (even if you don't have time to dig into the code). Or if you have any specific ideas on what I might be able to do troubleshoot this problem.
There is a lot of relevant code associated with my solution...rather than trying to copy and paste it all in this post I think the most effective and efficient way of "sharing" it with you is to point you to my public Github account where the code is located and provide a map to the relevant files within the project.
First the full set of code can be found on my Github account at: gitHub site
Within this project here is where you can find the relevant sections of code:
app/views/application.html.erb : List of external libraries (e.g., jQuery, bootstrap files, etc.)
app/views/portfolio_items/show.html.erb : HTML for page including Carousel
app/assets/javascripts/jet.js : see what I tried lines 17-20, 199-202. I'm not sure if I really need to include javascript as it didn't really seem to affect the behavior of the solution. So I ultimately commented it out.
app/assets/stylesheets/jet.css.erb : Lines 2332-2354
Note 1: you'll see that in my javascript file I'm using both $(window).load(function ()... and `$(document).ready(function() {' functions. I have to admit that I'm a bit fuzzy on what these two functions do other than generally make sure that the items on the page load before the javascript starts to run. I leveraged parts of my template from a theme and I noticed that they used both of these functions in their theme so I don't think this is the cause of my issues...but thought I would reference it just in case.
Note 2: I'm not sure it is relevant but I'm also using another Carousel solution (caroufredsel) on the same page with the Bootstrap Carousel. I don't think there is any conflict as the theme I borrowed from did the same thing...but I thought I would mention it.
UPDATE: I've continued to try and resolve my issue (i.e., Bootstrap Carousel next/prev buttons don't advance images) and stumbled upon something interesting that could be the key to fixing my issue. Specifically
When I "close" the $(document).ready" statement immediately as follows:
'$(document).ready(function() {});'
in my javascript "app/assets/javascripts/jet.js" the Bootstrap Carousel behaves as I would expect (prev/next controls advance images when clicked on).
Unfortunately making the change breaks the other carousel functionality (caroufredsel) at the bottom of the web page (i.e., instead of only showing 3 elements at a time in caroufredsel it shows all of the items and the controls for caroufredsel then don't work). I really need to wrap other jQuery code in the $(document).ready functionality...but when I do the Bootstrap prev/next controls don't work properly.
Anybody have any suggestions on what is going on here and how I could fix it?
Here is the full version of the jet.js file:
function scroll_to(clicked_link, nav_height) {
var element_class = clicked_link.attr('href').replace('#', '.');
var scroll_to = 0;
if(element_class != '.top-content') {
element_class += '-container';
scroll_to = $(element_class).offset().top - nav_height;
}
if($(window).scrollTop() != scroll_to) {
$('html, body').stop().animate({scrollTop: scroll_to}, 1000);
}
}
$(document).ready(function() {
// Bootstrap Carousel -- Tried each of the following lines but neither of them helped
// $('#carousel-generic-example').carousel()
// $('.carousel').carousel()
// $('#carousel-generic-example').carousel()});
// {
// 'prev'
// 'next'
// pause: true,
// interval: false,
// keyboard: true
// }
// jQuery('#carousel-generic-example').carousel();
// Pretty photo script
$("a[data-rel^='prettyPhoto']").prettyPhoto({
theme: 'light_square',
social_tools: false,
hook: 'data-rel'
});
// ------------------------------------------------------------------------------------------
// Code below attempted to dynamically change glyphicons used on web page separator
// to avoid having to distinct CSS code for every separator (e.g., blog-separator, project-separator, etc)
// Unfortunately I couldn't get this to work...this code displays the character string
// for the blog glyphicon (i.e., e043) rather than the actual glyphicon. StackOverflow (http://stackoverflow.com/questions/5041494/manipulating-css-pseudo-elements-such-as-before-and-after-using-jquery?lq=1) from Blazemonger (#3) suggest it may only work for strings (maybe not hex values)
// So I'm assuming i can't dynamically insert glyphicons.
// ------------------------------------------------------------------------------------------
// var regExp = /\#([a-z]+)/;
//
// $(".menu-items a").on('click', function () {
// var href = $(this).attr('href');
// var matches = regExp.exec(href);
// switch(matches[1]) {
// case "home":
// alert(href);
//
// break;
// case "about":
// alert(href);
// break;
// case "projects":
// alert(href);
// break;
// case "blog":
// $('.separator-line').attr('data-content', '\e043');
// // $(this).attr('data-content', '\e043');
// // $(".separator-line::after.content").attr('glyphicon-code',"\e043");
// var separatorCode = $(this).attr('data-content', '\e043').val();
// alert(separatorCode);
// break;
// case "contact":
// alert(href)
// break;
// }
// });
// -------------------------------------------------------------------------------
// Portfolio Javascript to load images
// var $container = $('.container');
//
// $container.imagesLoaded( function() {
// $container.masonry({
// itemSelector : '.post-box',
// columnWidth : '.post-box',
// transitionDuration : 0
// });
// });
$(".truncateIt").dotdotdot({
// configuration goes here
/* The text to add as ellipsis. */
ellipsis : '... ',
/* How to cut off the text/html: 'word'/'letter'/'children' */
wrap : 'word',
/* Wrap-option fallback to 'letter' for long words */
fallbackToLetter: true,
/* jQuery-selector for the element to keep and put after the ellipsis. */
after : 'a.next',
/* Whether to update the ellipsis: true/'window' */
watch : false,
/* Optionally set a max-height, if null, the height will be measured. */
height : 60,
/* Deviation for the height-option. */
tolerance : 0,
/* Callback function that is fired after the ellipsis is added,
receives two parameters: isTruncated(boolean), orgContent(string). */
callback : function( isTruncated, orgContent ) {},
lastCharacter : {
/* Remove these characters from the end of the truncated text. */
remove : [ ' ', ',', ';', '.', '!', '?' ],
/* Don't add an ellipsis if this array contains
the last character of the truncated text. */
noEllipsis : []
}
});
// Scroll location for buttons on banner page
$('a.scroll-link').on('click', function(e) {
e.preventDefault();
scroll_to($(this), $('nav').outerHeight());
});
// Link and activate WOW.js
new WOW().init();
$(".nav a").on("click", function(){
$(".nav").find(".active").removeClass("active");
$(this).parent().addClass("active");
});
// Smooth scrolling logic
$('a[href*=#]:not([href=#])').click(function() {
if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'')
|| location.hostname == this.hostname) {
var target = $(this.hash);
target = target.length ? target : $('[name=' + this.hash.slice(1) +']');
if (target.length) {
$('html,body').animate({
scrollTop: target.offset().top
}, 1000);
return false;
}
}
});
$(".cnbox").each(function () {
var nheight = $(this).find(".nbox").height();
$(this).find(".cbox").css("height", nheight + 50);
});
}); // /document.ready()
var caroufredsel = function () {
$('#caroufredsel-portfolio-container').carouFredSel({
responsive: true,
scroll: 1,
circular: false,
infinite: false,
items: {
visible: {
min: 1,
max: 3
}
},
prev: '#portfolio-prev',
next: '#portfolio-next',
auto: {
play: false
}
});
$('#caroufredsel-blog-posts-container').carouFredSel({
responsive: true,
scroll: 1,
circular: false,
infinite: false,
items: {
visible: {
min: 1,
max: 3
}
},
prev: '#blog-posts-prev',
next: '#blog-posts-next',
auto: {
play: false
}
});
};
// Isotope Portfolio
var $container = $('.portfolio-container');
var $blogcontainer = $('.posts-wrap');
var $filter = $('.portfolio-filter');
$(window).load(function () {
// Bootstrap Carousel -- Tried each of the following lines but neither of them helped
// jQuery('.carousel').carousel();
// jQuery('#carousel-generic-example').carousel();
caroufredsel();
// Initialize Isotope
$container.isotope({
itemSelector: '.portfolio-item-wrapper'
});
$blogcontainer.isotope({
itemSelector: '.article-wrap'
});
$('.portfolio-filter a').click(function () {
var selector = $(this).attr('data-filter');
$container.isotope({ filter: selector });
return false;
});
$filter.find('a').click(function () {
$filter.find('a').parent().removeClass('active');
$(this).parent().addClass('active');
});
});
$(window).smartresize(function () {
$container.isotope('reLayout');
$blogcontainer.isotope('reLayout');
});
$(window).resize(function () {
caroufredsel();
});
Cheers.

After much trial and error I found the solution through trial and error. As it turns out the $(document).ready(function() { had to be closed (i.e., }); immediately before the Smooth Scrolling logic (i.e., code that starts with $('a[href*=#]:not([href=#])').click(function() {).
I'm not completely sure why the "close" has to be placed there and not after the Smooth scrolling logic.
If anyone has an explanation I'd love to hear why...As I mentioned I discovered the solution largely by trial and error.

Bootstrap needs normally a JQuery file to overcome this error. So, better embed it in your file and it works when online.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>

Related

Capturing escape event for Fullscreen in Highcharts

I need to get an event for escape key from fullscreen in highcharts so that I can adjust the height of the container after escaping from fullscreen.
Highcharts requests fullscreen from the browser.
You could listen for various fullscreenchange events, and do some action based on it:
if (document.addEventListener) {
document.addEventListener('webkitfullscreenchange', exitHandler, false);
document.addEventListener('mozfullscreenchange', exitHandler, false);
document.addEventListener('fullscreenchange', exitHandler, false);
document.addEventListener('MSFullscreenChange', exitHandler, false);
}
function exitHandler() {
if (!document.webkitIsFullScreen && !document.mozFullScreen && !document.msFullscreenElement) {
console.log('Exiting fullscreen. Doing chart stuff.');
setContainerHeight(); // do your magic
}
}
See this JSFiddle demonstration or see this discussion on the general case of detecting fullscreening.
While the above works, I thought I'd throw out my solution as it wasn't ideal for my environment (multiple charts on the same page, as described here; partials linked to modules that have different needs).
I ended up using the Highcharts responsive callback option to execute code when a chart is exiting fullscreen mode.
responsive: {
rules: [{
condition: {
// A callback function to gain complete control on when the responsive rule applies. Return true if it applies
callback: function () {
if (this.chartHeight > (window.innerHeight / 2) || this.chartWidth > (window.innerWidth / 2)) {
console.log('responsive cb true:', this.renderTo.id);
_fsChartID = this.renderTo.id;
return true;
} else {
console.log('responsive cb false:', this.renderTo.id);
if (this.renderTo.id === _fsChartID) { // only hit when exiting fullscreen
_fsChartID = null; // reset _fsChartID to prevent infinite loop
this.redraw(); // call whatever function you need when exiting fullscreen
}
return false;
}
}
}
}]
}
Essentially:
Define a variable: _fsChartID to keep track of the which chart is in fullscreen mode. For me, this was defined as a global variable within the module it was needed in.
Update this variable to the correct chart id whenever a chart enters full screen mode.
If a chart fails the fullscreen test, check and see if its the same ID as the chart that entered fullscreen.
If so, reset the _fsChartID variable and do what you need
Else, return false as normal
Note that I simply called this.redraw() because my issue was related to the chart not redrawing correctly when exiting full screen.

Draggable with Vue.js, not being able to return to original position

I'm attempting to have an element's draggable functionality depend on a click event. I'm using jquery-ui's draggable method (within a vue.js instance).
In my Vue instance I have these two data properties: isVisible and a isDraggable. They assume a truthy or falsy value each time the user clicks a button. On my methods object I have the following:
methods: {
toggleBox: function() {
this.IsVisible = !this.IsVisible;
this.isDraggable = !this.isDraggable;
}
}
I'm using the destroy method in order to have the targeted element return to its original position (documentation here). However, I am not getting the intended result, as can be seen in the jsfiddle below. The following is one of many (unsuccessful) attemtps to tackle this issue:
ready: function() {
this.$nextTick(function() {
if (this.isDraggable == true) {
$('.box').draggable({
containment: "window"
})
} else if (this.isDraggable == false) {
$('.box').draggable(
"destroy"
)
}
})
}
Jsfiddle here. I wonder what I'm doing wrong here? Any hint appreciated.
The ready function only gets called once, during initialization of the vm element. Whenever you click on the "toggle" button, there's nothing that tells the nextTick method to execute. I'm not at all familiar with the vue api, so there probably will be a way to do what you want using the nextTick method.
Given my lack of knowledge regarding the api, I came up with a solution that seemed the most straightforward for your requirements i.e. updating the toggleBox method to check the isDraggable property and resetting the position of the box according to its value.
If you introduce other elements, you'd need to implement a solution that takes into account all of the default positions and re-apply them when you click the "toggle" button.
toggleBox: function() {
this.IsVisible = !this.IsVisible;
this.isDraggable = !this.isDraggable;
if (this.isDraggable) {
$('.box').draggable({
containment: "window"
})
} else if (!this.isDraggable) {
$('.box').offset({ top: 8, left: 8});
}
}
Fiddle example
Adding to #Yass's answer above, if instead of hard-coding the offset's top position of the element .box , you wanted to calculate it, here's one way to do it (which is useful in those cases where the browser's window changes size for instance):
toggleBox: function() {
this.IsVisible = !this.IsVisible;
this.isDraggable = !this.isDraggable;
var body = document.body.getBoundingClientRect();
var element = document.querySelector('.box').getBoundingClientRect();
var topPos = body.height - element.height;
if (this.isDraggable) {
$('.box').draggable({
containment: "window"
})
}
else if (!this.isDraggable) {
$('.box').offset({
top: this.topPos,
left: 8});
}
}

Jquery ui shake effect keeps trigering

Strange issue.
Using jquery ui effect like this:
<a href="in" style="position:absolute;" ><img src="images/img.png" id="perlabot" ></a>
$('#perlabot').on('mouseenter', function () {
$(this).effect("shake", { times:2, distance: 3}, 120);
});
And it works but on IE and Firefox the image keeps shaking all the time even if the mouse is right in the middle of the image. it seems that moving image trigers mouseenter event all the time??
Cannot fix this, strange issue. On chrome it trigers just once.
I didn't find a real solution to your problem but you could easily avoid it by checking if a variable has a certain value and reset it if the user leaves the area.
var active = false;
$('#perlabot').on('mouseenter', function () {
if (active === false) {
active = true;
$(this).effect("shake", {
times: 2,
distance: 3
}, 120);
}
}).mouseleave(function () {
active = false;
});
Might not be the smartest way to solve it but it works fine in every browser I tested it (Firefox, Chrome, Opera, IE 10 and 9)
jsfiddle
Try this option. Similar concept to the above answer, but I think more robust. (no global status variable for example)
function shakeIt(obj)
{
obj.mouseleave(function () {
obj.on("mouseenter", function () { shakeIt(obj); });
obj.off("mouseleave");
});
obj.off("mouseenter");
obj.effect("shake", { distance: "3", times: "2" }, 120);
}
$("#perlabot").on("mouseenter", function () { shakeIt($(this)); });

How do I stop my fixed navigation from moving like this when the virtual keyboard opens in Mobile Safari?

I understand that mobile safari has a lot of bugs around fixed elements, but for the most part I've managed to get my layout working correctly until I added a much needed text input to the fixed navigation at the bottom. Now when the user focuses on the text input element and the virtual keyboard appears, my navigation, which is otherwise always fixed at the bottom of the page, jumps up to a really strange spot in the middle of the page.
I'd add some of my code to this post, but I wouldn't be sure where to start. That navigation is fixed at the bottom and positioned to the left and bottom 0, and 100% width. From there, I don't know what's going on, I can only assume it's a mobile safari bug.
It also appears to lose it's position fixed and become relative, only while the text input element is focused on and the virtual keyboard is open.
http://dansajin.com/2012/12/07/fix-position-fixed/ this is one of the solutions proposed. Seems worth a shot.
In short: set fixed elements to position:absolute when any input is focused and reset them when that element is blurred
.header {
position: fixed;
}
.footer {
position: fixed;
}
.fixfixed .header,
.fixfixed .footer {
position: absolute;
}
and
if ('ontouchstart' in window) {
/* cache dom references */
var $body = $('body');
/* bind events */
$(document)
.on('focus', 'input', function() {
$body.addClass('fixfixed');
})
.on('blur', 'input', function() {
$body.removeClass('fixfixed');
});
}
The solutions on the top are some ways to go and fix the problem, but I think adding extra css class or using moderniz we are complicating things.If you want a more simple solution, here is a non-modernizr non-extra-css but pure jquery solution and work on every device and browsers I use this fix on all my projects
if ('ontouchstart' in window) {
$(document).on('focus', 'textarea,input,select', function() {
$('.navbar.navbar-fixed-top').css('position', 'absolute');
}).on('blur', 'textarea,input,select', function() {
$('.navbar.navbar-fixed-top').css('position', '');
});
}
I had a similar problem, but I found a workaround by adding the following css class to the body element on input focus and then removing it again on unfocus:
.u-oh {
overflow: hidden;
height: 100%;
width: 100%;
position: fixed;
}
Taking from what sylowgreen did, the key is to fix the body on entering the input. Thus:
$("#myInput").on("focus", function () {
$("body").css("position", "fixed");
});
$("#myInput").on("blur", function () {
$("body").css("position", "static");
});
Add javascript like this:
$(function() {
var $body;
if ('ontouchstart' in window) {
$body = $("body");
document.addEventListener('focusin', function() {
return $body.addClass("fixfixed");
});
return document.addEventListener('focusout', function() {
$body.removeClass("fixfixed");
return setTimeout(function() {
return $(window).scrollLeft(0);
}, 20);
});
}
});
and add class like this:
.fixfixed header{
position: absolute;
}
you can reference this article: http://dansajin.com/2012/12/07/fix-position-fixed/
I really like the solution above. I packaged it up into a little jQuery plugin so I could:
Set which parent gets the class
Set which elements this applies to (don't forget "textarea" and "select").
Set what the parent class name is
Allow it to be chained
Allow it to be used multiple times
Code example:
$.fn.mobileFix = function (options) {
var $parent = $(this),
$fixedElements = $(options.fixedElements);
$(document)
.on('focus', options.inputElements, function(e) {
$parent.addClass(options.addClass);
})
.on('blur', options.inputElements, function(e) {
$parent.removeClass(options.addClass);
// Fix for some scenarios where you need to start scrolling
setTimeout(function() {
$(document).scrollTop($(document).scrollTop())
}, 1);
});
return this; // Allowing chaining
};
// Only on touch devices
if (Modernizr.touch) {
$("body").mobileFix({ // Pass parent to apply to
inputElements: "input,textarea,select", // Pass activation child elements
addClass: "fixfixed" // Pass class name
});
}
I use this jQuery script:
var focus = 0;
var yourInput = $(".yourInputClass");
yourInput.focusin(function(){
if(!focus) {
yourInput.blur();
$("html, body").scrollTop($(document).height());
focus = 1;
}
if(focus) {
yourInput.focus();
focus = 0;
}
});
Works perfectly for me.
The focusin and focusout events seem to be better suited to this problem than the focus and blur events since the former bubble up to the root element. See this answer on SO.
Personally I use AngularJS, so I implemented it like this:
$window.document.body.addEventListener('focusin', function(event) {
var element = event.target;
var tagName = element.tagName.toLowerCase();
if(!$rootScope.inputOverlay && (tagName === 'input' || tagName === 'textarea' || tagName === 'select')) {
$rootScope.$apply(function() {
$rootScope.inputOverlay = true;
});
}
});
$window.document.body.addEventListener('focusout', function() {
if($rootScope.inputOverlay) {
$rootScope.$apply(function() {
$rootScope.inputOverlay = false;
});
}
});
Note: I am conditionally running this script if this is mobile Safari.
I put an ng-class attribute on my navbar:
<div class="navbar navbar-default navbar-fixed-top" ng-class="{'navbar-absolute': inputOverlay}">
using the following CSS:
.navbar-absolute {
position: absolute !important;
}
You can read more about focusin here and focusout here.
Test this one. It works. I just test it.
$(document).on('focus','input', function() {
setTimeout(function() {
$('#footer1').css('position', 'absolute');
$('#header1').css('position', 'absolute');
}, 0);
});
$(document).on('blur','input', function() {
setTimeout(function() {
$('#footer1').css('position', 'fixed');
$('#header1').css('position', 'fixed');
}, 800);
});
None of these solutions worked for me because my DOM is complicated and I have dynamic infinite scroll pages, so I had to create my own.
Background: I am using a fixed header and an element further down that sticks below it once the user scrolls that far down. This element has a search input field. In addition, I have dynamic pages added during forward and backwards scroll.
Problem: In iOS, anytime the user clicked on the input in the fixed element, the browser would scroll all the way to the top of the page. This not only caused undesired behavior, it also triggered my dynamic page add at the top of the page.
Expected Solution: No scroll in iOS (none at all) when the user clicks on the input in the sticky element.
Solution:
/*Returns a function, that, as long as it continues to be invoked, will not
be triggered. The function will be called after it stops being called for
N milliseconds. If `immediate` is passed, trigger the function on the
leading edge, instead of the trailing.*/
function debounce(func, wait, immediate) {
var timeout;
return function () {
var context = this, args = arguments;
var later = function () {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
function is_iOS() {
var iDevices = [
'iPad Simulator',
'iPhone Simulator',
'iPod Simulator',
'iPad',
'iPhone',
'iPod'
];
while (iDevices.length) {
if (navigator.platform === iDevices.pop()) { return true; }
}
return false;
}
$(document).on("scrollstop", debounce(function () {
//console.log("Stopped scrolling!");
if (is_iOS()) {
var yScrollPos = $(document).scrollTop();
if (yScrollPos > 200) { //200 here to offset my fixed header (50px) and top banner (150px)
$('#searchBarDiv').css('position', 'absolute');
$('#searchBarDiv').css('top', yScrollPos + 50 + 'px'); //50 for fixed header
}
else {
$('#searchBarDiv').css('position', 'inherit');
}
}
},250,true));
$(document).on("scrollstart", debounce(function () {
//console.log("Started scrolling!");
if (is_iOS()) {
var yScrollPos = $(document).scrollTop();
if (yScrollPos > 200) { //200 here to offset my fixed header (50px) and top banner (150px)
$('#searchBarDiv').css('position', 'fixed');
$('#searchBarDiv').css('width', '100%');
$('#searchBarDiv').css('top', '50px'); //50 for fixed header
}
}
},250,true));
Requirements: JQuery mobile is required for the startsroll and stopscroll functions to work.
Debounce is included to smooth out any lag created by the sticky element.
Tested in iOS10.
I wasn't having any luck with the solution proposed by Dan Sajin. Perhaps the bug has changed since he wrote that blog post, but on iOS 7.1, the bug will always surface when the position is changed back to fixed after the input is blurred, even if you delay until the software keyboard is hidden completely. The solution I came to involves waiting for a touchstart event rather than the blur event since the fixed element always snaps back into proper position when the page is scrolled.
if (Modernizr.touch) {
var $el, focused;
$el = $('body');
focused = false;
$(document).on('focus', 'input, textarea, select', function() {
focused = true;
$el.addClass('u-fixedFix');
}).on('touchstart', 'input, textarea, select', function() {
// always execute this function after the `focus` handler:
setTimeout(function() {
if (focused) {
return $el.removeClass('u-fixedFix');
}
}, 1);
});
}
HTH

iScroll scrollToElement not working with jQuery Mobile

I have something similar to this iScroll example: http://cubiq.org/dropbox/iscroll4/examples/simple/
Except that I'm using jQuery mobile (i.e., the header, footer, and content are set using jQuery Mobile). Everything is running smoothly except for scrollToElement.
Is there any way to get scrollToElement working when using jQuery Mobile and iScroll?
Here's the iScroll script I currently have:
var myScroll;
function loaded() {
myScroll = new iScroll('wrapper');
}
document.addEventListener('touchmove', function (e) { e.preventDefault(); }, false);
document.addEventListener('DOMContentLoaded', function () { setTimeout(loaded, 200);}, false);
EDIT: Forgot to mention what I'm trying to achieve. In the iScroll example mentioned above, I'm trying to scroll to a specific row. The only problem is that jQuery Mobile prevents scrollToElement from working for some reason.
Also make sure that you're using a timeout
setTimeout(function () {
myScroll.scrollToElement(".elementClass", "0s");
myScroll.refresh();
}, 0);
The workaround I have found is to capture the elements position and then use scrollToPage():
var w = $("#showselectedauthors").offset().top;
// ...
$.storeScroller.scrollToPage(0, w);
Of course for this to work you have to capture the position when the element is visible or the offset will be meaningless. You can do this when the page is built but before the scroller is initialized.
In my case the element is visible and I capture w at that time. I then refresh some content and refresh the scroller. After I do that I want to make sure the element is still visible.
Case anyone needs to scroll to a jQuery Object here's my code .
Make sure you're calling this method inside a setTimeout and your "iscroll" object is defined .
function scrollToElement($element) {
if ($element.size() > 1) {
throw new Error("Cannot be a node!");
};
var offset = $element.offset().top;
var to = -(offset - iscroll.y);
to = (iscroll.maxScrollY > to) ? iscroll.maxScrollY : to;
iscroll.scrollTo(0, to);
}

Resources