Sign up ×
Stack Overflow is a community of 4.7 million programmers, just like you, helping each other. Join them; it only takes a minute:

I am building a console like application using AngularJS. One of my requirements is that the div containing the console is scrolled down automatically. I achieved that using a directive that is monitoring the content and adjusting the scrollTop property of the div accordingly:

app.directive('autoScroll', function () {
    return {
        restrict: 'A',
        link: function (scope, element, attrs, ctrls) {
            var scrollToBottom = function () {
                element[0].scrollTop = element[0].scrollHeight;
            };
            scope.$watchCollection('outputLines', scrollToBottom);
        }
    };
});

The first approach to get lines displayed was to use ng-repeat in combination with an unordered list and the curly brackets syntax for binding:

<div auto-scroll id="withHtml" class="list">
    <ul>
        <li ng-repeat="line in outputLines">{{line.text}}</li>
        <li>>> {{currentInput}}</li>
    </ul>
</div>

This worked beautifully as you can see in the green output area in this fiddle. The input line (the one that starts with >> is always visible.

enter image description here

But one of the requirements also is to render HTML in the output lines. I thus started using the ngSanitize module and switched from curly brackets syntax to using the ng-bind-html directive:

<div auto-scroll id="withHtml" class="list">
    <ul>
        <li ng-repeat="line in outputLines" ng-bind-html="line.text"></li>
        <li>>> {{currentInput}}</li>
    </ul>
</div>

That results in the input line always moving out of the visible area. As you can see in the red output area in the fiddle mentioned above:

enter image description here

The output generated looks the same in both cases. So here's my question: Why does scrolling behave differently depending on whether I use the curly brackets syntax or the ng-bind-html directive?

share|improve this question
up vote 1 down vote accepted

It's a timing issue.

If you do the following:

var scrollToBottom = function () {
  console.log(element[0].scrollHeight);
  element[0].scrollTop = element[0].scrollHeight;
};

You will notice that after a few inputs the scrollHeight at the time of setting scrollTop will differ.

I haven't dug deeper into the source code to see what causes this, but you can use $evalAsync to make sure the code is run after the DOM has been maniuplated by Angular, but before the browser renders:

var scrollToBottom = function() {
  scope.$evalAsync(function() {
    element[0].scrollTop = element[0].scrollHeight;
  });
};

Demo: http://jsfiddle.net/cBny9/

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.