Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • Home
  • SEARCH
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 959741
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 16, 20262026-05-16T01:04:26+00:00 2026-05-16T01:04:26+00:00

First off, I know I can copy "this" on instantiation, but that doesn’t work

  • 0

First off, I know I can copy "this" on instantiation, but that doesn’t work here.

Basically I’m writing something to track people interacting with Youtube videos.

I got this working fine for one video at a time. But I want it to work on pages with multiple Youtube videos as well, so I converted the code to a class so I can create a new instance of it for each video on the page.

The problem is when trying to bind to the Youtube event listener for state changes. For "non-class" code, it looks like this:

var o = document.getElementById( id );
o.addEventListener("onStateChange", "onPlayerStateChange" );

(onPlayerStateChange being the function I wrote to track state changes in the video)

(I’m also aware that addEventListener won’t work with MSIE but I’m not worrying about that yet)

But when I’m inside a class, I have to use "this" to refer to another function in that class. Here’s what the code looks like:

this.o = document.getElementById( id );
this.o.addEventListener("onStateChange", "this.onPlayerStateChange" );

When it’s written like this, this.onPlayerStateChange is never called. I’ve tried copying "this" into another variable, e.g. "me", but that doesn’t work either. The onPlayerStateChange function is defined within the "this" scope before I do this:

var me = this;
this.o = document.getElementById( id );
this.o.addEventListener("onStateChange", "me.onPlayerStateChange" );

Any insights?

Looking through other similar questions here, all of them are using jQuery, and I think doing it that way might work if I did it that way. But I don’t want to use jQuery, because this is going to be deployed on random third party sites. I love jQuery but I don’t want it to be a requirement to use this.

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-16T01:04:27+00:00Added an answer on May 16, 2026 at 1:04 am

    Ok, I got this all working. It’s a bit of an ugly hack but it works. Basically I’m storing each new instance of the class in an array, and I’m passing the array key (1, 2, etc) into the class, so it can refer to itself externally as needed in a few key places.

    The places I need the class to refer to itself externally are the string I pass to addEventListener, and within a few setTimeout functions, where “this” apparently loses its context (as far as I can tell anyways, because the only way I could them working was changing “this” to use external references instead.

    Here’s the full code.

    On the page that has Youtube videos, they are injected using swfobject. The _ytmeta object stores the titles for each video. It’s optional, but it’s the only way to log the title of a video, because Youtube’s API does not give it to you. This means you have to know the title up front, but the point is simply that if you want the title to show up in our reports, you have to create this object:

    <div id='yt1'></div>
    
    <script src='youtube.js'></script>
    <script src='swfobject.js'></script>
    <script>
    var _ytmeta = {}
    _ytmeta.yt1 = { 'title': 'Moonwalking in Walmart' };
    
    var params = { allowScriptAccess: "always" };
    swfobject.embedSWF("http://www.youtube.com/v/gE1ZvCnwkYk?enablejsapi=1&playerapiid=yt1", "yt1", "425", "356", "8", null, null, params );
    </script>
    

    So we’re including the swfobject javascript code, as well as the youtube.js file, which will be hosted on our server and included on the pages you want to track videos.

    Here are the contents of youtube.js:

    // we're storing each youtube object (video) in an array, and passing the array key into the class, so the class instance can refer to itself externally
    // this is necessary for two reasons
    // first, the event listener function we pass to Youtube has to be globally accessible, so passing "this.blah" doesn't work
    // it has to be passed as a string also, so putting "this" in quotes makes it lose its special meaning
    // second, when we create timeout functions, the meaning of "this" inside that function loses its scope, so we have to refer to the class externally from there too.
    
    // _yt is the global youtube array that stores each youtube object. yti is the array key, incremented automatically for each new object created
    var _yt = [], _yti = 0;
    
    // this is the function the youtube player calls once it's loaded. 
    // each time it's called, it creates a new object in the global array, and passes the array key into the class so the class can refer to itself externally
    function onYouTubePlayerReady( id ) {
      _yti++;
      _yt[ _yti ] = new _yta( id, _yti );
    }
    
    function _yta( id, i ) {
    
      if( !id || !i ) return;
    
      this.id = id;
      this.mytime;
      this.scrubTimer;
      this.startTimer;
      this.last = 'none';
      this.scrubbing = false;
    
      this.o = document.getElementById( this.id );
      this.o.addEventListener("onStateChange", "_yt["+i+"].onPlayerStateChange" );
    
      this.onPlayerStateChange = function( newState ) {
    
        // some events rely on a timer to determine what action was performed, we clear it on every state change.
        if( this.myTime != undefined ) clearTimeout( this.myTime );
    
        // pause - happens when clicking pause, or seeking
        // that's why a timeout is used, so if we're seeking, once it starts playing again, we log it as a seek and kill the timer that would have logged the pause
        // we're only giving it 2 seconds to start playing again though. that should be enough for most users.
        // if we happen to log a pause during the seek - so be it.
        if( newState == '2' ) {
          this.myTime = setTimeout( function() {
            _yt[i].videoLog('pause');
            _yt[i].last = 'pause';
            _yt[i].scrubbing = false;
            }, 2000 );
          if( this.scrubbing == false ){
            this.last = 'pre-scrub';
            this.scrubbing = true;
          }
        }
    
        // play
        else if( newState == '1' ) {
    
          switch( this.last ) {
    
            case 'none':
              this.killTimers();
              this.startTimer = setInterval( this.startRun, 200 );
              break;
    
            case 'pause':
              this.myTime = setTimeout( function() {
                _yt[i].videoLog('play');
                _yt[i].last = 'play';
              }, 2000 );
              break;
    
            case 'pre-scrub':
              this.killTimers();
              this.scrubTimer = setInterval( this.scrubRun, 200 );
              break;
          }
        }
    
        // end
        else if( newState == '0' ) {
          this.last = 'none';
          this.videoLog('end');
        }
      }
    
    
      // have to use external calls here because these are set as timeouts, which makes "this" change context (apparently)
      this.scrubRun = function() {
        _yt[i].videoLog('seek');
        _yt[i].killTimers();
        _yt[i].last = 'scrub';
        _yt[i].scrubbing = false;
      }
      this.startRun = function() {
        _yt[i].videoLog('play');
        _yt[i].killTimers();
        _yt[i].last = 'start';
      }
    
      this.killTimers = function() {
        if( this.startTimer ) {
          clearInterval( this.startTimer );
          this.startTimer = null;
        }
        if( this.scrubTimer ){
          clearInterval( this.scrubTimer );
          this.scrubTimer = null;
        }
      }
    
      this.videoLog = function( action ) {
        clicky.video( action, this.videoTime(), this.videoURL(), this.videoTitle());
      }
    
      this.videoTime = function() {
        return Math.round( this.o.getCurrentTime() );
      }
    
      this.videoURL = function() {
        return this.o.getVideoUrl().split('&')[0]; // remove any extra parameters - we just want the first one, which is the video ID.
      }
    
      this.videoTitle = function() {
        // titles have to be defined in an external object
        if( window['_ytmeta'] ) return window['_ytmeta'][ this.id ].title || '';
      }
    }
    

    Hopefully, someone in the future will find this helpful, because it was a serious pain in the ass to get it working!

    Thank you everyone who posted their ideas here. 🙂

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

First off, it may seem that I'm asking for subjective opinions, but that's not
First off, I know next to nothing about language theory, and I barely know
First, I know there are methods off of the generic List<> class already in
First off, there's a bit of background to this issue available on my blog:
First off, I'm working on an app that's written such that some of your
First off, let me start off that I am not a .net developer. The
First off, this question is ripped out from this question. I did it because
First off the html row looks like this: <tr class=evenColor> blahblah TheTextIneed blahblah and
First off, I read all of the suggested questions that sounded halfway relevant and
First off, I am using Windows XP. I have multiple hard drives and it

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.