I have a simple chat application on a web page, i have an issue when trying to autoscroll the div only when the scroll bar is at the bottom.
I've tried this:
$("#line").load("x.php");
var d = $('#line');
d.scrollTop(d.prop("scrollHeight"));
var refreshId = setInterval(function(){
var isEnd = $('#line')[0].offsetHeight + $('#line')[0].scrollTop == $('#line')[0].scrollHeight;
$('#line').append('<p class="triangle-isosceles right"><img src="images/user-img.jpg" style="height: 30px;padding-right: 5px;"/><b>Douglas:</b> prueba<br><small>Fecha</small></p>');
console.log(isEnd);
if(isEnd){
var scrolle = $("#line").prop("scrollHeight") - $('#line').height();
$("div#line").scrollTop(scrolle) ;
}
}, 1000);
So when doing this using the append function works great, the issue comes when instead of append i refresh the content of the div using load()
$("#line").load("x.php");
var d = $('#line');
d.scrollTop(d.prop("scrollHeight"));
var refreshId = setInterval(function(){
var isEnd = $('#line')[0].offsetHeight + $('#line')[0].scrollTop == $('#line')[0].scrollHeight;
$("#line").load('ajax/x.php');
console.log(isEnd);
if(isEnd){
var scrolle = $("#line").prop("scrollHeight") - $('#line').height();
$("div#line").scrollTop(scrolle) ;
}
}, 1000);
This seems to break the autoscroll because the div is not autoscrolling on new messages.
Appreciate your help
Finally i achieved my goal by doing this:
var scrolled = false;
$(window).load(function() {
$("#line").load("x.php");
var d = $('#line');
d.scrollTop(d.prop("scrollHeight"));
$("#line").on('scroll', function(){
scrolled=true;
});
var refreshId = setInterval(function(){
$("#line").load('x.php');
if($('#line')[0].offsetHeight + $('#line')[0].scrollTop == $('#linea')[0].scrollHeight){
scrolled=false;
}
updateScroll();
}, 1000);
});
function updateScroll(){
if(!scrolled){
$("#linea").scrollTop($("#linea").prop("scrollHeight"));
}
}
I define a var named scrolled and set it to false (the user didn't scroll the div), after that i load the conversations on the div #line, then automatically scroll to bottom of that div to show the last messages, add a listener to the scroll event, in case the user scroll the div then i set scrolled to true so the div do not scroll automatically.
Do the refresh of the div element every second and check if the current scroll position is equal to the height of the div, if so then set the scrolled to false.
After that i run a function called updateScroll to scroll to the bottom if the scrolled var is false.
Related
I have a list of chat messages inside a div and want to scroll to the bottom each time an element is added. I tried calling a function that selects the last item and uses scrollIntoView().
scrollToElement:function() {
const el = this.$el.getElementsByClassName('message');
if (el) {
el[el.length-1].scrollIntoView({behavior: "smooth"});
}
}
The issue is that it scrolls to the top of the selected element and not to the bottom of it which is needed in order to include the entire element into view.
I expected:
I got:
Every time you append a new chat message to the chat container - you need to scroll the chat container to its bottom edge. You can do that with a simple assignment:
this.$refs.chatContainer.scrollTop = this.$refs.chatContainer.scrollHeight;
Please note that the scrolling must be performed inside $nextTick to ensure that the new chat message has been added to the DOM.
My advice is to use a Vue directive on the chat container which will automatically scroll to the bottom every time a new chat message has been added:
function scrollToBottom(el)
{
el.scrollTop = el.scrollHeight;
}
// Monitors an element and scrolls to the bottom if a new child is added
// (always:false = prevent scrolling if user manually scrolled up)
// <div class="messages" v-chat-scroll="{always: false}">
// <div class="message" v-for="msg in messages">{{ msg }}</div>
// </div>
Vue.directive('chat-scroll',
{
bind: function(el, binding)
{
var timeout, scrolled = false;
el.addEventListener('scroll', function(e)
{
if (timeout) window.clearTimeout(timeout);
timeout = window.setTimeout(function()
{
scrolled = el.scrollTop + el.clientHeight + 1 < el.scrollHeight;
}, 200);
});
(new MutationObserver(function(e)
{
var config = binding.value || {};
var pause = config.always === false && scrolled;
if (pause || e[e.length - 1].addedNodes.length != 1) return;
scrollToBottom(el);
})).observe(el, {childList: true});
},
inserted: scrollToBottom
});
Chat does not scroll to bottom after jquery load method
My chat works by load new messages inside a scrolling div with jquery load method but div do not scroll to bottom when new messages are loaded, also I can't run out.scrollTop = out.scrollHeight; with the div load because as it loads every second when user click scroll to older messages it just make the scroll control flash all the time.
I am using this example of this fiddle
http://jsfiddle.net/dotnetCarpenter/KpM5j/
It all looks to work fine but it's not working when I use with jquery .load() method
my index.php
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.3.0/jquery.min.js"></script>
<script>
setInterval(
function() {
$('#out').load('load_chat.php');
var messageBody = document.querySelector('#out');
out.scrollTop = out.scrollHeight - out.clientHeight;
}, 3000);
</script>
<script>
var out = document.getElementById("out");
var c = 0;
var add = setInterval(function() {
// allow 1px inaccuracy by adding 1
var isScrolledToBottom = out.scrollHeight - out.clientHeight <= out.scrollTop + 1;
console.log(out.scrollHeight - out.clientHeight, out.scrollTop + 1);
var newElement = document.createElement("div");
newElement.innerHTML = c++;
out.appendChild(newElement);
// scroll to bottom if isScrolledToBotto
if (isScrolledToBottom)
out.scrollTop = out.scrollHeight - out.clientHeight;
}, 1000);
</script>
<div id="out" style="overflow-y: scroll; height:80px;"></div>
I need to load the load_chat.php and also keep the page scrolling to the bottom
I can't use
var out = document.getElementById('out');
out.scrollTop = out.scrollHeight;
inside the load by Interval function, because it makes scrolling very weird, can someone help?
The general idea to the site i am designing is to scroll through a set of menu items horizontally and incrementally underneath a static div that will magnify(increase dimensions and pt size) the contents of a menu items. I don't really need help with the magnify portion because i think it's as simple as adding a mag class to any of the menuItem divs that go underneath the static div. I have been messing with this for a few weeks and the code I have for incrementally scrolling, so far, is this:
$(document).ready(function () {
currentScrollPos = $('#scrollableDiv').scrollTop(120); //sets default scroll pos
/*The incrementScroll function is passed arguments currentScrollPos and UserScroll which are variables that i have initiated earlier in the program, and then initiates a for loop.
-The first statement sets up the variables: nextScrollPos as equal to the currentScrollPos(which by default is 120px) plus 240px(the distance to next menuItem), prevScrollPos as equal to the currentScrollPos(which by default is 120px) minus 240px(the distance to next menuItem).
-The second Statement checks to see if the user has scrolled using var userScroll
-The third statement sets: var CurrentScroll equal to the new scroll position and var userScroll to false*/
function incrementScroll(currentScrollPos, userScroll) {
for (var nextScrollPos = parseInt(currentScrollPos + 240, 10),
prevScrollPos = parseInt(currentScrollPos - 240, 10); //end first statement
userScroll == 'true'; console.log('dude'), //end second statement and begining of third
currentScrollPos = scrollTop(), userScroll = 'false') {
if (scrollTop() < currentScrollPos) {
$('#scrollableDiv').animate({
scrollTop: (parseInt(prevScrollPos, 10))
}, 200);
console.log('scrolln up')
} else if (scrollTop() > currentScrollPos) {
$('#scrollableDiv').animate({
scrollTop: (parseInt(nextScrollPos, 10))
}, 200);
console.log('scrolln down')//fire when
}
}
}
$('#scrollableDiv').scroll(function () {
userScroll = 'true';
_.debounce(incrementScroll, 200); //controls the amount of times the incrementScroll function is called
console.log('straight scrolln')
});
});
I have found a variety of solutions that are nigh close: such as a plugin that snaps to the next or previous div horizontally demo, another solution that also snaps and is based on setTimeout demo, but nothing that nails incrementally scrolling through divs. I also found a way to control the rate at which a user may scroll through the menuItems using debounce which is included in the above code.
The console.logs inside the loop do not fire when I demo the code in jsfiddle which leads me to believe the problem lies within the loop. I'm a noob though so it could be in syntax or anywhere else in the code for that matter. Also in the second demo, i have provided the css for the horizontal static div, but the moment I put it in my html it keeps the js from working.
I would like to write the code instead of using a plugin and any help would be appreciated! Also, thank you ahead of time!
Try this fiddle. Menu container height is 960px to show 4 menu items. "Zoom" div is positioned absolutely at top. When you scroll mouse over this div, menu items shifts to top/bottom. I had to add additional div to bottom to be able to scroll to last 3 menu items. JS code:
jQuery(document).ready(function($){
var current = 0;
var menu = $('.menu-container').scrollTop(0);
var items = menu.find('.menu-item');
var zoom = $('.zoom');
function isVerticalScroll(event){
var e = event.originalEvent;
if (e.axis && e.axis === e.HORIZONTAL_AXIS)
return false;
if (e.wheelDeltaX)
return false;
return true;
}
function handleMouseScroll(event){
if(isVerticalScroll(event)){
var delta = event.originalEvent.wheelDelta * -1 || event.originalEvent.detail;
current += (delta > 0 ? 1 : -1);
if(current < 0)
current = 0;
if(current >= items.length){
current = items.length - 1;
}
menu.stop().animate({
"scrollTop": current * 240
}, 300);
items.removeClass('current').eq(current).addClass('current');
event && event.preventDefault();
return false;
}
}
zoom.on({
"MozMousePixelScroll": handleMouseScroll,
"mousewheel": handleMouseScroll
});
});
Hope it will help.
Background
I am trying to create an infinite scrolling table inside a fixed position div. The problem is that all the solutions I come across use the window height and document scrollTop to calculate if the user has scrolled to the bottom of the screen.
Problem
I have tried to create a jQuery plugin that can calculate if a user has scrolled to the bottom of a fixed div with overflow: scroll; set.
My approach has been to create a wrapper div (the div with a fixed position and overflow: scroll) that wraps the table, I also place another div at the bottom of the table. I then try calculate if the wrapper.scrollTop() is greater than the bottom div position.top every time the wrapper is scrolled. I then load the new records and append them to the table body.
$.fn.isScrolledTo = function () {
var element = $(this);
var bottom = element.find('.bottom');
$(element).scroll(function () {
if (element.scrollTop() >= bottom.position().top) {
var tableBody = element.find("tbody");
tableBody.append(tableBody.html());
}
});
};
$('.fixed').isScrolledTo();
See Example http://jsfiddle.net/leviputna/v4q3a/
Question
Clearly my current example is not correct. My question is how to I detect when a user has scrolled to the bottom of a fixed div with overflow:scroll set?
Using the bottom element is a bit clunky, I think. Instead, why not use the scrollHeight and height to test once the scrollable area has run out.
$.fn.isScrolledTo = function () {
var element = this,
tableBody = this.find("tbody");
element.scroll(function(){
if( element.scrollTop() >= element[0].scrollHeight-element.height()){
tableBody.append(tableBody.html());
}
});
};
$('.fixed').isScrolledTo();
EDIT (12/30/14):
A DRYer version of the plugin might be much more re-usable:
$.fn.whenScrolledToBottom = function (cback_fxn) {
this.on('scroll',this,function(){
if( ev.data.scrollTop() >= ev.data[0].scrollHeight - ev.data.height()){
return cback_fxn.apply(ev.data, arguments)
}
});
};
Plugin Usage:
var $fixed = $('.fixed'),
$tableBody = $fixed.find("tbody");
$fixed.whenScrolledToBottom(function(){
// Load more data..
$tableBody.append($tableBody.html());
});
I have modified your code to handle the scroll event with a timer threshold:
$.fn.isScrolledTo = function () {
var element = $(this);
var bottom = element.find('.bottom');
$(element).scroll(function(){
if (this.timer) clearTimeout(this.timer);
this.timer=setTimeout(function(){
if( element.scrollTop() >= bottom.position().top){
var tableBody = element.find("tbody");
tableBody.append(tableBody.html());
}
},300);
});
};
$('.fixed').isScrolledTo();
The issue you are having is that as you scroll, new scroll event is being generated. Your code might have other issues, but this is a start.
I'm currently using a combination of smooth scroll and IDs/anchor tags to scroll to content on my site. The code below is getting the ID of the next 'section' in the DOM, and adding it's ID as the 'view next section' href, so once it's clicked, it'll scroll to the top of that div. Then, it iterates through, updating the href with the next ID each time etc until the last section is seen and it scrolls back to the top. Pretty straightforward.
The only problem is that the 'sections' are fullscreen images, so as it's scrolling to the top of the next section, if you resize the browser, the top position of that section (where we scrolled to) has moved, and means the position is lost.
I've created a JSFiddle. You can see this happening after you click the arrow to visit the next section then resize the window: http://jsfiddle.net/WFQ9t/3/
I'm wanting to keep this top position fixed at all times so even if you resize the browser, the scroll position is updated to reflect this.
Thanks in advance,
R
var firstSectionID = $('body .each-section').eq(1).attr('id');
$('.next-section').attr('href', '#' + firstSectionID);
var i = 1;
$('.next-section').click(function() {
var nextSectionID = $('body .each-section').eq(i).attr('id');
i++;
$('.next-section').attr('href', '#' + nextSectionID);
var numberOfSections = $('body .each-section').length;
var lastSectionID = $('body .each-section').eq(numberOfSections).attr('id');
if ($('.next-section').attr('href') == '#' + lastSectionID ) {
$('.next-section').attr('href', '#introduction');
i = 1;
}
});
Ok, Please check out this fiddle: http://jsfiddle.net/WFQ9t/9/
The few things I did were:
Made some global variables to handle the screen number (which screen you're on and also the initial window height. You will use this when the screen loads and also when you click on the .next-session arrow.
var initWinHeight = $(window).height();
var numSection = 0;
Then I tossed those variables into your resizeContent() function
resizeContent(initWinHeight, numSection)
so that it will work on load and resize
I made the body move around where it needs to, to accomodate for the movement of the divs (I still don't understand what divs are moving when the regular animation happens).
$('body').css({
top: (((windowHeight - initWinHeight)*numSection)*-1) + "px"
});
Then in your click function, I add 1 to the section number, reset the initial window height and then also reset the body to top:0. The normal animation you have already puts the next section at the top of the page.
numSection++;
initWinHeight = $(window).height();
$('body').css({top:"0px"}, 1000);
Finally, I reset the numSections counter when you reach the last page (You might have to make this 0 instead of 1)
numSection = 0;
The fiddle has all of this in the correct places, these are just the steps I took to change the code.
Here is a solution that i found, but I dont use anchor links at this point, i use classes
Here is my HTML code:
<section class="section">
Section 1
</section>
<section class="section">
Section 2
</section>
<section class="section">
Section 3
</section>
<section class="section">
Section 4
</section>
And here is my jQuery/Javascript code,
I actually used a preety simple way:
$('.section').first().addClass('active');
/* handle the mousewheel event together with
DOMMouseScroll to work on cross browser */
$(document).on('mousewheel DOMMouseScroll', function (e) {
e.preventDefault();//prevent the default mousewheel scrolling
var active = $('.section.active');
//get the delta to determine the mousewheel scrol UP and DOWN
var delta = e.originalEvent.detail < 0 || e.originalEvent.wheelDelta > 0 ? 1 : -1;
//if the delta value is negative, the user is scrolling down
if (delta < 0) {
next = active.next();
//check if the next section exist and animate the anchoring
if (next.hasClass('section')) {
var timer = setTimeout(function () {
$('body, html').animate({
scrollTop: next.offset().top
}, 800);
next.addClass('active')
.siblings().removeClass('active');
clearTimeout(timer);
}, 200);
}
} else {
prev = active.prev();
if (prev.length) {
var timer = setTimeout(function () {
$('body, html').animate({
scrollTop: prev.offset().top
}, 800);
prev.addClass('active')
.siblings().removeClass('active');
clearTimeout(timer);
}, 200);
}
}
});
/*THE SIMPLE SOLUTION*/
$(window).resize(function(){
var active = $('.section.active')
$('body, html').animate({
scrollTop: active.offset().top
}, 10);
});