0

I'm new to OOP in Javascript and I'm having some difficulties.

I wanted to manage objects that do something when they are in viewport.

The code I used

Here is the code that I've implemented. Please note that the problem is especially on the row window.addEventListener( 'scroll', this.i_am_watching.bind(this), false ); that does not work as expected.

<html><head>

    <style>
        .content { background: #f8f8f8; padding: 20px; height: 1000px; }
        .person { padding: 20px; font-size: 20px; line-height: 20px; }
        .person.mark { background: pink; }
        .person.peter { background: lightblue; }
        .person.albert { background: lightgreen; }
        div + div { margin-top: 20px; }
        div { border: 1px solid black; }
        #console { position: fixed; top: 10px; right: 10px; width: 50%; height: 300px; overflow: auto; border: 3px solid black; background: white; }
    </style>

</head><body>

    <div id="console"></div>
    <div class="content">...some content...</div>
    <div id="mark_div" class="person mark">MARK</div>
    <div class="content">...some content...</div>
    <div id="peter_div" class="person peter">PETER</div>
    <div class="content">...some content...</div>
    <div id="albert_div" class="person albert">ALBERT</div>
    <div class="content">...some content...</div>

    <script>

        function Person( name, div_id )
        {
            // properties
            this.label = name;
            this.div = document.getElementById( div_id );           

            // auxiliary function
            this.is_in_viewport = function( el )
            {
                var rect = el.getBoundingClientRect();
                return (
                    rect.top+el.offsetHeight >= 0 &&
                    rect.left >= 0 &&
                    rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
                    rect.right <= (window.innerWidth || document.documentElement.clientWidth)
                );
            }

            // i_am_watching
            this.i_am_watching = function()
            {
                if( this.is_in_viewport( this.div ) ) document.getElementById('console').innerHTML += "I'm watching <b>"+name+"<br>" ;
            }

            // listener
            window.addEventListener( 'scroll', this.i_am_watching, false );
        }

        Person( "mark", "mark_div" );
        Person( "peter", "peter_div" );
        Person( "albert", "albert_div" );

    </script>

</body></html>

Fiddle: https://jsfiddle.net/bd3182zw/2/

The problem

The problem is that the listener fires only and always when Albert is on the viewport. And when it fires, all objects execute the i_am_watching method.

bind doesn't work

As suggested in the MDN reference for EventTarget.addEventListener() (section "The value of this within the handler"), I've tried to add .bind(this) after the function called by the listener, in order to ensure that this applies to the right object; but as you can see,m it doesn't work.

What I'm doing wrong?

Marco Panichi
  • 1,068
  • 1
  • 18
  • 31
  • *"`bind` doesn't work"* You do definitely need the `bind` in that line (or [one of the other solutions](http://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-context-inside-a-callback)). That doesn't mean there isn't a *different* problem *as well*. Presumably the calculation in `is_in_viewport` isn't quite right (when you do have the `bind` so it gets called). Your best bet for figuring that out is to debug it. – T.J. Crowder Jan 03 '18 at 15:36

1 Answers1

2

this in Person function is window the global object when acalled like this.

To instanciate a class object, please create it with a new operator.

    new Person( "mark", "mark_div" );
    new Person( "peter", "peter_div" );
    new Person( "albert", "albert_div" );

Then the Person has his own context.

PS: Don't forget your binding !

        // listener
        window.addEventListener( 'scroll', this.i_am_watching.bind( this ), false );
karkael
  • 431
  • 2
  • 9