6

I am trying to scroll to the bottom of a div #chat-feed with overflow set to auto and stay there unless a user scrolls that div's content up. If they scroll back down, the div should lock to the bottom and new content will be displayed at the bottom.

Known issues: I have tried implementing this answer with my code but I do not know Javascript well enough yet to get it working. If content from chat-feed.php is taller than the container then the scroll stays at the top. It also seems like the answer given does not respect content loaded from an external file.

Key things: new content should show at the bottom and the div should scroll to the bottom when new content loads UNLESS the users has already scrolled up a bit. If the user scrolls back down, then it should lock to the bottom and new content be displayed at the bottom and be visible.

<div id="chat-feed" style="height: 200px; width: 300px; overflow: auto;"></div>


<script>
$(document).ready(function(){
    setInterval(function(){
        $('#chat-feed').load("chat-feed.php").fadeIn("slow");
    }, 1000);
});
</script>

Demo link

Community
  • 1
  • 1
Damien
  • 157
  • 5
  • 12

1 Answers1

1

On question you linked to, there is a better implementation https://stackoverflow.com/a/21067431/1544886.

I've reworked that author's code below:

$(document).ready(function() {

  var out = document.getElementById("chat-feed"); // outer container of messages
  var c = 0; // used only to make the fake messages different

  // generate some chatter every second
  setInterval(function() {

    //check current scroll position BEFORE message is appended to the container
    var isScrolledToBottom = checkIfScrolledBottom();

    // append new mesage here
    $('#chat-feed').append("<div>Some new chat..." + c++ + "</div>").fadeIn("slow");

    // scroll to bottom if scroll position had been at bottom prior
    scrollToBottom(isScrolledToBottom);

  }, 1000);

  function checkIfScrolledBottom() {
    // allow for 1px inaccuracy by adding 1
    return out.scrollHeight - out.clientHeight <= out.scrollTop + 1;
  }

  function scrollToBottom(scrollDown) {
    if (scrollDown)
      out.scrollTop = out.scrollHeight - out.clientHeight;
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div id="chat-feed" style="height: 150px; width: 300px; overflow: auto;"></div>

UPDATE

JQuery's .load() function deletes the associated element (chat-feed) and re-adds. This means that the out variable points to the old deleted element, not the new. The solution is update the out variable after executing a .load():

$('#chat-feed').load("chat-feed.php").fadeIn("slow");
out = document.getElementById("chat-feed"); // outer container of messages
Community
  • 1
  • 1
K Scandrett
  • 16,390
  • 4
  • 40
  • 65
  • I got this far but the desired effect does not appear to work when content is loaded from `chat-feed.php`. Also, if the content from `chat-feed.php` is already taller than the container, the scroll is at the top and you have to manually scroll down. The file `chat-feed.php` is just a bunch of `

    hey

    ` lines. Can you verify with externally loaded content and then add a line to the file and see if it scrolls as desired?
    – Damien Mar 06 '17 at 01:08
  • Added explanation of how to handle .load() – K Scandrett Mar 06 '17 at 02:26
  • With your help and some poking and prodding I got it to work for the most part. The initial position of the scrollbar stayed at the top so I had to add a delayed trigger to the bottom of the script to force the scrollbar to the bottom of the container div `setTimeout(function() { $("#chat-feed").scrollTop($("#chat-feed")[0].scrollHeight);}, 1500);` Is there a more elegant way of forcing the scrollbar to the bottom upon initial execution of the script? – Damien Mar 06 '17 at 03:57
  • I tested it earlier locally with `.load()` using a html file that was bigger than the container. It worked fine for me (using the `out = ...` addition after the .load() as noted in the updated answer), so can't see why it wouldn't for you. I did however use the latest version of jQuery. As to your query it would be better to use: `out = document.getElementById("chat-feed");scrollToBottom(true);` instead – K Scandrett Mar 06 '17 at 04:08
  • You could also try removing the `fadein()`. I can't remember if I included that in my test, but probably didn't – K Scandrett Mar 06 '17 at 04:14
  • I am using jQuery 2.1.3 and still cannot get it to scroll to the bottom without a delayed execution even with removing the fade option. Everything works as it should even with the delayed scroll. Thank you for all of your help! – Damien Mar 06 '17 at 04:24
  • If you want to post your revised code as a new question, post the link to it here and I'll take a look – K Scandrett Mar 06 '17 at 04:29
  • After more testing, it appears it is not functioning as it should. It appeared to work because I was removing a line from the file as a new one was loaded in so the height of the container never actually changed. Is there a place I can load my code? jfiddle will not let you link to an external file for the chat-feed.php. Can I direct message you a link to my site that this is running on? – Damien Mar 08 '17 at 07:00
  • The problem will be in the front end, as 'load' just does what it does. But you could provide the url to your backhand service in the question if you wanted – K Scandrett Mar 08 '17 at 20:06
  • Demo link added – Damien Mar 08 '17 at 23:11
  • You need to put the `scrollToBottom(isScrolledToBottom);` in the `success` method of the ajax call. Currently, because the ajax call is asynchronous that line runs before the ajax call returns, and not after – K Scandrett Mar 08 '17 at 23:15
  • If you post your demo html and JS as a new question I'll provide working code as an answer – K Scandrett Mar 08 '17 at 23:19
  • There will not be a button for a user to insert data so there will not be a success. The button now is just to insert data on demand for testing. The content will be displayed to users without interaction and they will basically watch a live chat feed remotely. Can this still be done without a `success` method? Here is a link to the [new question with full code](http://stackoverflow.com/questions/42683924/jquery-scroll-and-anchor-to-bottom-of-ajax-driven-div-unless-user-scrolls-up-w) – Damien Mar 08 '17 at 23:31