0

I'm pretty new to javascript so i need some help.
I'm trying to make a simple plugin (only for learn of course, to understand things better ), but i got in some troubles and some help will be appreciated.
My plugin is basic, I'm trying to animate some content on scroll , so here is my code:
JS:

(function() {
  //=============================
  //=======CONSTRUCTOR===========
  //=============================
  this.hAnimate = function() {
    this.hanimate = null;
    this.el = null;


    //default options
    var defaults = {
      class : 'hanimate'
    }

   // Create options and extend defaults
   if (arguments[0] && typeof arguments[0] === "object") {
     this.options = extendDefaults(defaults, arguments[0]);
   }

  }
  //==============================
  //===========FUNCTIONS==========
  //==============================

  hAnimate.prototype.init = function() {

    window.addEventListener('scroll' , function(){
      this.el = document.querySelector(this.options.class);
    var distanceY = window.pageYOffset || document.documentElement.srollTop,
        scrollDelay = this.el.getAttribute('data-scroll');

        if ( distanceY > scrollDelay ){
          this.el.classList.add('scrolled');
        }
        else{
          if(this.el.classList.contains('scrolled')){
            this.el.classList.remove('scrolled')
          }
        }
     });
   }
  function extendDefaults(source, properties) {
    var property;
    for (property in properties) {
      if (properties.hasOwnProperty(property)) {
        source[property] = properties[property];
      }
    }
    return source;
  }

}());

HTML:

<header class='hanimate' data-scroll='1000' data-effect='bg-red'>
    <h1>This is my header</h1>
  </header>
  <main class='wrapper'>

  </main>
  <script src='scripts/hAnimate.js'></script>
  <script>
     window.onload = function(){
       new hAnimate().init();
     }
  </script>

and CSS:

.wrapper{
  width:80%;
  margin:0 auto;
  min-height:5000px}

.hanimate{
  position:fixed;
  top:0;
  left:0;
  width:100%;
  height:5em;
  display:flex;
  align-items:center;
  justify-content:center;
  background:#f2f2f2;
}

[data-effect='bg-red']{
  transition:background .7s;
}
.scrolled[data-effect='bg-red']{
  background:red;
}

so when I'm trying to run it trows me an error in console

ReferenceError: options is not defined

this.el = document.querySelector(this.options.class);

demo here

UPDATE
So i did some research but simply I just can't figure it, I am a beginner , I know, but I simply don't understand, this is my updated code:

// Create an immediately invoked functional expression to wrap our code
;(function(window) {
  'use strict';
  function extend( a, b ) {
        for( var key in b ) {
            if( b.hasOwnProperty( key ) ) {
                a[key] = b[key];
            }
        }
        return a;
    }
  // Define our constructor
   function hAnimate(el, options) {
     this.el = document.querySelector(el);
     this.options = extend( this.defaults, options );
     this.init();
  }

  hAnimate.prototype = {
    defaults : {
            classToAdd : 'scrolled'
        },
    init: function() {
      window.addEventListener('scroll', function(){
          var self = this,
              distanceY = window.pageYOffset || document.documentElement.scrollTop,
              scrollDel = 100;

          if (distanceY > scrollDel) {
            this.el.classList.add(this.options.classToAdd);
          } else {
              if (this.el.classList.contains(this.options.classToAdd)) {
                this.el.classList.remove(this.options.classToAdd);
              }
          }
      });
  }

}
window.hAnimate = hAnimate;

})(window);


document.addEventListener('DOMContentLoaded', function() {
  //var el = document.querySelector('.hAnimate');
  new hAnimate('.hanimate', {classToAdd : 'green'});
});  

and error is

TypeError: this.el is undefined, i tried self.el too but don't work either.
Instead this work :

// Create an immediately invoked functional expression to wrap our code
;(function(window) {
  'use strict';
  function extend( a, b ) {
        for( var key in b ) {
            if( b.hasOwnProperty( key ) ) {
                a[key] = b[key];
            }
        }
        return a;
    }
  // Define our constructor
   function plugin(el, options) {
     this.el = document.querySelector(el);
     this.options = extend( this.defaults, options );
     this.init();
  }

  plugin.prototype = {
    defaults : {
            color : 'red'
        },
    init: function() {
      this.el.style.color = this.options.color;
  }

}
window.plugin = plugin;

})(window);

document.addEventListener('DOMContentLoaded', function() {

//var el = document.querySelector('.plugin');
new plugin('.plugin', {color: 'blue'});

});


I hope someone can give me some advices , I really want to get familiar with javascript

Alin Mercasi
  • 83
  • 10
  • See this if it can help: https://tommcfarlin.com/javascript-reference-error-is-not-defined/ – The Guest Apr 17 '15 at 19:53
  • It is most likely because this.options is never set. Although you define default options, you never assign them in case argument[0] is not an object. So maybe add after line 18: `else{ this.options = defaults; }` – kecer Apr 17 '15 at 19:57
  • no doesn't help, I have an error somewhere , but I don't know where @kecer i tried but unfortunately doesn't work – Alin Mercasi Apr 17 '15 at 20:03
  • [link](http://stackoverflow.com/questions/1369004/this-keyword-in-event-methods-when-using-javascript-prototype-object) This is what you are looking for. When you are saying *this* when defining event handler, you are reffering to the DOM element where the event took place, not the hAnimate object. You will need to rewrite your code – kecer Apr 17 '15 at 20:18

1 Answers1

0

So as I was saying in my comment, the problem you have is similar to this one.

Easily put, when you define an event handler, this refers to an element where the event happened, rather than your object. Simple workaround for you, if you do not want to rewrite your code, would be creating an alias for reference to the object when defining init behavior.

hAnimate.prototype.init = function() {
    var obj = this;
    window.addEventListener('scroll' , function(){
        ....
    }
}

Therefore, in the function defined as a scroll-event handler, obj would refer to the hAnimate instance and this to an element. So all you need to do is replace all relevant occurrences of "this" with "obj".

There is another bug in your code though, this line to be exact:

this.el = document.querySelector(this.options.class);

Assuming this.options.class holds only class name, using it as querySelector will not yield any result (since it would be interpreted as a tag name instead of class name). Use this:

obj.el = document.getElementsByClassName(obj.options.class)[0];

Where [0] is used to get only first element. Just a note, you could rather use #id, but that is up to you.

Here is modified fiddle

Note: It does not work for me on jsfiddle, but then again, nothing is. I wonder why. It runs good on localhost though.

Community
  • 1
  • 1
kecer
  • 3,031
  • 2
  • 21
  • 24
  • doesn't work for me, however a have an idea based on your answer , which should work, i will update the code an make some test and if will work I will accept your answer – Alin Mercasi Apr 18 '15 at 11:26