Lazy loading occasionally doesn't work in angular
Asked Answered
Z

2

14

I am encountering some strange behavior for the following code.

    function linkFunc(scope, element, attribute) {
        var page = angular.element($window);

        page.bind('scroll', function() {

            var windowHeight = "innerHeight" in window ? window.innerHeight : document.documentElement.offsetHeight;
            var body = document.body, html = document.documentElement;
            var docHeight = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight,  html.scrollHeight, html.offsetHeight);
            var windowBottom = windowHeight + window.pageYOffset;

            if (windowBottom >= docHeight) {
                scope.$apply(attribute.myDirective);
            }
        });
    }

The above is a piece of code that detects if the bottom of the page is reached, if its reached it will call whatever function bind to myDirective

The main issue is that most of the time the lazy loading works, and myDirective gets sucessfully called. However some of the times the lazy loading won't work, and I wasn't able to reproduce the bug.

I tried different screen size, different browser, but it seems like the bug just happens randomly.

Maybe someone have this happened to them before, and can point me a direction?

Edit:

More information

I was able to reproduce the bug after a bit of experimenting.

Basically, when the zoom in percentage of the browser is < 100 % , window.pageY returns a decimal value that is slightly inaccurate which cause windowBottom to be off by a 0.1 to 0.9

eg.

            console.log(windowBottom); // 1646.7747712336175
            console.log(docHeight);    // 1647

Does anyone know why this happens?

Edit 2:

The above behavior is also non deterministic, but the decimal part is true.

Zygophyllaceous answered 28/7, 2016 at 17:58 Comment(7)
this is a rather unusual way to design an angular directive; it's counter to the design principles of angular to start tying the execution of JavaScript to specific UI events.Larainelarboard
You do not happen to have the chrome dev console at the bottom of the screen? Seems to me that it can have a bit quirky affect on the height perception of similar code.Cain
@Cain I didn't have chrome dev console at the bottom of the screen, although I did tried that, but the behavior is still non deterministic.Zygophyllaceous
While this isn't necessarily a fix, it may still be a fix... since it's off by 0.1 to 0.9, couldn't you use floor or ceiling?Hafler
@ChrisStanley that is exactly what I did, but I want to know the reason though.Zygophyllaceous
You can just do Math.floor or Math.Ceil on the value so you will get proper values without decimals.Vend
Can't you use an "infinite loading" module for angular (or vanilla js) and change it to load your directive ? It handles the bottom of page detection rather nicely.Vanzandt
L
3

0.1 + 0.2 !== 0.3

This one is an oddity not just in JavaScript; it’s actually a prevailing problem in computer science, and it affects many languages. The output of this is 0.30000000000000004.

This has to do with an issue called machine precision. When JavaScript tries to execute the line above, it converts the values to their binary equivalents. This is where the problem starts. 0.1 is not really 0.1 but rather its binary equivalent, which is a near-ish (but not identical) value. In essence, as soon as you write the values, they are doomed to lose their precision. You might have just wanted two simple decimals, but what you get, as Chris Pine notes, is binary floating-point arithmetic. Sort of like wanting your text translated into Russian but getting Belorussian. Similar, but not the same.

You can read more here. Without digging into browser source, I would guess that your problem stems from this.

Luxuriate answered 15/8, 2016 at 19:3 Comment(3)
Downvoted. Does not answer the OP's question or solves the issue.Ilmenite
Up vote. It does answer the question. If you read the addition to the question it turns out the issue is from how JavaScript handles mathematical operations.Garling
@Ilmenite "Does anyone know why this happens?" is ultimately OP's question as he's already discovered the culprit on his ownLuxuriate
L
3

Given the floating-point precision issues, you may want to loosen you condition to check instead if the two values are less than 1 pixel different. For example:

if (Math.abs(windowBottom - docHeight) < 1) {
    scope.$apply(attribute.myDirective);
}
Liggins answered 16/8, 2016 at 21:1 Comment(1)
Great! this helped me mcgraphix :)Ricercar

© 2022 - 2024 — McMap. All rights reserved.