I am building an app in Ionic, and there are certain functions that load new sets of data into an existing view.
When I do this, sometimes if I have scrolled down, and the new data takes less space than the previous one, I am left with a blank screen until I scroll back up to where the new data is.
To prevent this, I am running an $ionicScrollDelegate.resize(); which works, but it doesn't refresh. If I swipe (to reload data) twice, it resizes the view and bumps the scroll up if necessary, however if I do it just once, the scroll resizes, however does not bring the user up automatically. They have to start scrolling first, then it snaps them back to a scroll area that actually has data present.
I managed to solve this by using a watch:
$scope.$watch(function(scope) { return scope.projects },
function() {
$ionicScrollDelegate.$getByHandle('taskScroll').resize();
}
);
But I do not want to use a $watch for performance reasons. I've tried using various methods to get this resize to work from the event that calls the data to be reloaded, including $apply, $evalAsync, $timeout...
None of them worked, except $timeout, but then only when the interval was 500ms. This tells me it is an issue with the speed at which the data is loading and that is why $watch worked cause it keeps looking.
Is there anything else I can do to make the resize work immediately? This is the code for the event handler function:
$scope.onSwipeRight = function () {
var operatingDate = appContextService.getOperatingDate()
.subtract(1,'days')
.startOf('day');
var pastDate = moment().subtract(1,'years')
.startOf('year')
.startOf('isoWeek');
if (isSwipeEnabled && operatingDate.isAfter(pastDate)) {
slideInCacheValidation(-1);
}
// Just one attempt at fixing this below, I've tried so many things that do not work...
$scope.$eval( function() {
$ionicScrollDelegate.$getByHandle('taskScroll').resize();
});
};
Related
I want to scroll to the bottom of a webpage using JS and, looking online, most people say to use
window.scrollTo(0,document.body.scrollHeight);
However the page I want to scroll down changes its height as you reach the bottom (it continuously loads more and more of the page) so its height is not fixed. The eventual height also varies (thus I cannot just scroll to the final height of the page) so I need some way of scrolling until it determines it has reached the bottom (it cannot scroll any further).
If you have infinite scroll, you actually need to incorporate that in your design. E.g. scrollToBottom should look like this:
function scrollToBottom(lastOffset) {
const offset = document.body.scrollHeight;
// check if no more scrolling required.
if (lastOffset === offset) {
return;
}
// if it is, go to bottom.
window.scrollTo(0, offset);
// Now, trigger your `loadMore` logic, whatever it might be, then call scrollToBottom again.
triggerLoadMore().then(() => scrollToBottom(offset));
// or triggerLoadMore(() => scrollToBottom(offset));
}
// call this somewhere after your initial load.
Now, triggerLoadMore, erm, triggers your loadMore logic. I included two versions in the above code, one being promise-based, the commented one being callback-based. It should call back your function (scrollToBottom) when it has loaded more and put it on the screen. How you do that, depends on what you use, and is possibly another question.
Now, there's a third option here, that your trigger is something that you cannot call directly, because it's tied to window.scroll event or some such logic. In that case, you need to write this bit of logic at the end of such function flow - load more, render on screen, scroll. Which then triggers the cycle again.
#Zlatko answer is the best performance. However, you can use this one in every context :
window.addEventListener( 'resize', function(){
window.scrollTo(0,document.body.scrollHeight);
});
Sounds like you need to reach bottom of the page, wait for load and scroll to bottom again. You can't reach the end of the page where you cannot know the end.
function scroll_and_wait(){
return new Promise(
function(resolve, reject){
setTimeout(function(){
resolve(window.scrollTo(0,document.body.scrollHeight));
}, 500);})}
async function scroller(n){while(n>0){await scroll_and_wait();n=n-1;}}
scroller(5)
Calling scroller function will scroll to to bottom of the page as many times as you specify with 500ms pause for loading.
I know there are a couple of questions to scrollTop already out there but I haven't really seen anything resembling my problem.
Using jquery 1.7.2 on an IE9 we have a page with three Tabs (JqueryUI).
The Data is connected and that resulted in us only having the current tab on the page. Changing tabs will remove the unseen one and reload the one we jump into.
The Scroll-Positions are stored correctly in variables on the base page but trying to set that position in the document-ready-function does not work.
An alert shows the correct number, so the function is actually called but the scrollbar does not move.
Calling the same function with a button on the page afterwards however works perfectly.
The document-ready-function on the tab's jsp is quite simple:
<script type="text/javascript">
jQuery(document).ready(function(){
setAhaScrollbar();
});
</script>
and the called function is quite simple as well:
function setAhaScrollbar() {
var scrollWert = $('#scrollbarAnhaengeartikel').val();
alert(scrollWert);
$('#anhaengeGridScrollable').scrollTop(scrollWert);
}
Called from document-ready it does nothing. Called from a button later on it works fine.
The div where the scroll position is supposed to be set is defined with overflow: auto and a fixed height
crollTop( value )
Description: Set the current vertical position of the scroll bar for each of the set of matched elements.
.scrollTop( value )
value
Type: Number
An integer indicating the new position to set the scroll bar to.
More Information
As the documentationsaid value should be number.
Try
var scrollWert = Number($('#scrollbarAnhaengeartikel').val());
or
var scrollWert = parseInt($('#scrollbarAnhaengeartikel').val());
Apparently it was primarily a timing problem. Maybe there were still things going on when document ready fired.
Changing that function to
jQuery(document).ready(function(){
setTimeout("setAhaScrollbar()", 500);
});
did the trick so my problem is solved.
I have a several divs connected to one another using the endpoint connections to one another. As I do a zoom in or zoom out, I need to repaint all the UI components. The UI components are drawn using the jsPlumb library(jquery/javascript based). There is a method in jsplumb which forces the repaint but it is not working as the way I want it to do. Here it is what I am trying to do.
$("div#explanation .plus").click(function(){
jsPlumb.repaintEverything();
var strongFont = parseFloat($("div.window strong").css('font-size'));
var newStrongFont = strongFont + 2;
$("div.window ").animate({
'height':'+=20px', 'width':'+=20px'
},"medium");
$("div.window strong").animate({
fontSize:newStrongFont
},"medium");
//This is not working
jsPlumb.repaintEverything();
jsPlumb.repaintEverything();
//I am calling here another function to repaint the div windows one by one
repaintWindows();
});
var repaintWindows = function(){
var jjl;
for(jjl=1;jjl<=xmlLength;jjl++)
{
var windo = "window"+jjl;
//alert("Window is ::"+windo);
jsPlumb.repaint(windo);
alert("Window is ::"+windo);
//_addEndpoints(wind, ["LeftMiddle", "BottomCenter"], ["TopCenter", "RightMiddle"]);
}
alert("the value of jjl is ::"+jjl+" \nThe value of xmlLength is::"+xmlLength);
};
The problem here is if I remove the
//alert("Window is ::"+windo);
from the repaintWindows method for loop, the windows get repainted during the next cycle of call. I want the repaint to work at the same time. If I keep the alert, then it does repaint the window at the same time. As well, at the end I dont want any kind of alert over there.
Can somebody please tell me where am I going wrong.
Any help is appreciated.
Thanks!
not sure, but try this one
$(window).resize(function() {
jsPlumb.repaintEverything();
});
UPDATE:
I was able to get my scroller working as desired but I feel like I have hacked around the actual issue and would love it if anyone has a more solid answer, I've updated and noted in the snippets below the new jQuery I'm using.
I'm using iScroll-4 (http://cubiq.org/iscroll-4) for an iPad/Android web app, everything's working perfectly with the swipes and scrolling but I have a table of contents at the beginning of the app that allows users to jump to specific areas of the scroller --
I'm using the iScroll function scrollToElement(element, duration) in order to jump to the different areas. Also using scrollToPage(page, duration) to allow the user to manually navigate forward and backward one page at a time.
While watching the console logs the currPageX variable updates when I navigate with the scrollToPage function and when I swipe, but when using the scrollToElement the currPageX variable does not update.
Therefore if I jump to an element and then navigate forward with scrollToPage('next', 0) it will go backwards and navigate me to the next page after the table of contents.
I have tried using the scroll.refresh() function after scrollToElement, before, putting the function inside a timeout, etc. and I can't figure out why the currPageX is not updating.
Here's a snippet of the jQuery code that I'm using the two different functions:
// TO NAVIGATE FORWARD AND BACKWARDS
$('span.control').on('click', function() {
var slideDir = $(this).attr('data-dir');
if (slideDir == 'prev') {
var tehPg = tehScroll.currPageX-1;
} else if (slideDir == 'next') {
var tehPg = tehScroll.currPageX+1;
}
tehScroll.scrollToPage(tehPg, 0);
return false;
});
// TO JUMP FROM CONTENTS
$('li[data-page="toc"] span').on('click', function() {
var toPage = $(this).attr('data-page');
tehScroll.scrollToElement('li[data-page="'+toPage+'"]', 800);
// ADDED THE FOLLOWING LINE TO MANUALLY SET currPageX after scrolling!
tehScroll.currPageX = $('#slides li[data-page="'+toPage+'"]').index();
return false;
});
Did you consider using jquery-mobile-iscrollview widget plug-in? - there is a function scrollToPage(pageX, pageY, time), works well for me...
best
M
I'm asking a question very similar to this one—dare I say identical?
An example is currently in the bottom navigation on this page.
I'm looking to display the name and link of the next and previous page when a user hovers over their respective icons. I'm pretty sure my solution will entail binding or timers, neither of which I'm seeming to understand very well at the moment.
Currently, I have:
$(document).ready(function() {
var dropdown = $('span.hide_me');
var navigator = $('a.paginate_link');
dropdown.hide();
$(navigator).hover(function(){
$(this).siblings(dropdown).fadeIn();
}, function(){
setTimeout(function(){
dropdown.fadeOut();
}, 3000);
});
});
with its respective HTML (some ExpressionEngine code included—apologies):
<p class="older_entry">Older<span class="hide_me">Older entry:
<br />
{title}</span></p>
{/exp:weblog:next_entry}
<p class="blog_home">Blog Main<span class="hide_me">Back to the blog</span></p>
{exp:weblog:prev_entry weblog="blog"}
<p class="newer_entry">Newer<span class="hide_me">Newer entry:
<br />
{title}</span></p>
This is behaving pretty strangely at the moment. Sometimes it waits three seconds, sometimes it waits one second, sometimes it doesn't fade out altogether.
Essentially, I'm looking to fade in 'span.hide_me' on hover of the icons ('a.paginate_link'), and I'd like it to remain visible when users mouse over the span.
Think anyone could help walk me through this process and understand exactly how the timers and clearing of the timers is working?
Thanks so much, Stack Overflow. You guys have been incredible as I walk down this road of learning to make the internet.
If you just want to get it working, you can try to use a tooltip plugin like this one.
If you want to understand how this should be done: first, get rid of the timeout, and make it work without it. The difference (from the user's point of view) is very small, and it simplifies stuff (developing and debugging). After you get it working like you want, put the timeout back in.
Now, the problem is you don't really want to hide the shown element on the navigator mouse-out event. You want to hide it in its own mouse out event. So I think you can just pass the first argument to the navigator hover function, and add another hover to dropdowns, that will have an empty function as a first argument, and the hiding code in its second argument.
EDIT (according to your response to stefpet's answer)
I understand that you DO want the dropdown to disappear if the mouse moves out of the navigator, UNLESS its moved to the dropdown itself. This complicates a little, but here is how it can be done: on both types of items mouse-out event, you set a timer that calls a function that hides the dropdown. lets say the timer is 1 second. on both kind of item mouse-in even, you clear this timer (see the w3school page on timing for syntax, etc). plus, in the navigator's mouse-in you have to show the dropdown.
Another issue with the timer in your code is that it will always execute when mouse-out. Due to the 3 seconds delay you might very well trigger it again when mouse-over but since the timer still exist it will fade out despite you actually have the mouse over the element.
Moving the mouse back and forth quickly will trigger multiple timers.
Try to get it to work without the timer first, then (if really needed) add the additional complexity with the delay (which you must keep track of and remove/reset depending on state).
Here was the final working code, for anyone who comes across this again. Feel free to let me know if I could have improved it in any ways:
$(document).ready(function() {
var dropdown = $('span.hide_me');
var navigator = $('a.paginate_link');
dropdown.hide();
$(navigator).hover(function(){
clearTimeout(emptyTimer);
$(this).siblings(dropdown).fadeIn();
}, function(){
emptyTimer = setTimeout(function(){
dropdown.fadeOut();
}, 500);
});
$(dropdown).hover(function(){
clearTimeout(emptyTimer);
}, function(){
emptyTimer = setTimeout(function(){
dropdown.fadeOut();
}, 500);
});
});