0

Working on my framework again. Wanted to create a method to blink an element. I would need to set interval inside the method. So I thought this might work:

var optionalSelector = "$";

(function() {
    (this[arguments[0]] = function constructor(input) {
        if (!(this instanceof constructor)) { return new constructor(input); }
        this.elm = document.getElementById(input);
    }).prototype = {
        blink:      function() {
                        function changeDisplay() {
                            if (this.elm.style.display != "none") {
                                this.elm.style.display = "none";
                            } else {
                                this.elm.style.display = "block";
                            }
                        }
                        setInterval(changeDisplay, 1000);
                    },
    };
})(optionalSelector);

And calling the method $("anElmId").blink();

But it doesn't. Another function inside the method and there's also an interval. I guess this two messes things up. Like it doesn't recognize this.elm. Since I'm a newbie I couldn't figure out a way to fix this. Any ideas?

Fiddle

akinuri
  • 10,690
  • 10
  • 65
  • 102

1 Answers1

0

You should try some console.log statements in your code. When in Chrome or in Firefox (preferably with firebug plugin installed) you can press F12 to open the console and check out the output of your logs.

console.log(this)

In changeDisplay would reveal that this most likely is Window. To understand why you have to understand what this stands for in JavaScript. I like to call it the function invoking object as that most accurately describes it (in my opinion). See here for more details.

var optionalSelector = "$";
window[optionalSelector] = function constructor(input) {
  if (!(this instanceof constructor)) {
    return new constructor(input);
  }
  this.elm = document.getElementById(input);
  this.intervalid = 0;
  this.timeoutid = 0;
};
window[optionalSelector].prototype.blink = 
  function(interval, timeout) {
    this.intervalid = setInterval(this._callbacks.
      changeDisplay(this.elm), interval);
    this.timeoutid=setTimeout(this._callbacks.
      cancelInterval(this.intervalid),timeout);
    return this;
};
window[optionalSelector].prototype.cancel = function() {
  clearTimeout(this.timeoutid);
  clearInterval(this.intervalid);
  return this;
};
// I like to have callback functions (closures) in it's own
// scope so you can better control what variables
// are passed to it
window[optionalSelector].prototype._callbacks = {
  changeDisplay: function(elm) {
    return function() {
      if (elm.style.display !== "none") {
        elm.style.display = "none";
      } else {
        elm.style.display = "block";
      }
    };
  },
  cancelInterval:function(intervalid){
    return function(){
      clearInterval(intervalid);
    };
  }
};

var myBlinker = window[optionalSelector]
  ("hplogo").blink(200, 2000);
//cancel it
myBlinker.cancel();
//blink something else for 2 seconds
window[optionalSelector]("gbqfba").blink(200, 2000);

Went to google.com pressed F12 and ran the above code. It should work. More on the difference between prototype properties and instance properties here.

Community
  • 1
  • 1
HMR
  • 37,593
  • 24
  • 91
  • 160
  • Alright. Final code is like this: [Fiddle](http://jsfiddle.net/Apazm/3/). It seems to work. Though I have a question. You mentioned about clearing the interval. How can I achieve that? e.g. using the button in the fiddle. – akinuri Oct 24 '13 at 16:46
  • @akinuri I re formatted your code a bit since it kind of needlessly creates a closure for every function defined in `(function(){...}())` If you like to wrap the whole thing in a self invoking function you can still do so. – HMR Oct 24 '13 at 23:56
  • I think there are some things in this code that I need to process =) But since the actual problem is solved I'll accept this. – akinuri Oct 25 '13 at 16:06