JordanBarber
JordanBarber

Reputation: 2101

'This' in Object Oriented Javascript

I think that I currently write pretty good javascript, but am trying to move to a more Object Oriented approach. I am just starting with this so forgive my noob-ness. I was moving some of my functions over to objects and ran into this issue. Previously, I had an accordion function that worked like this:

jQuery(document).ready(function ($){

var accordionTrigger = $('.accordion-title');

function toggleAccordion() {
    // Set a variable for the accordion content
    var accordionContent = $('.accordion-container .accordion-content p');
    // Slide up any open content
    accordionContent.slideUp();
    // Remove any active classes
    accordionTrigger.removeClass("active");
    // If the sibling content is hidden
    if(!$(this).siblings().is(":visible")) {
        // slide it down
        $(this).siblings().slideDown();
        // add a class to the title so we can style the active state and change the svg
        $(this).addClass("active");
    }
}

accordionTrigger.on("click", toggleAccordion);

});

I have moved this over to an Object in my new set-up like this:

Accordion = {
accordionContent: '.accordion-container .accordion-content p',
accordionTrigger: '.accordion-title',
init: function() {
    jQuery(this.accordionTrigger).click(this.toggleAccordion.bind(this));
},
toggleAccordion: function() {
    // Slide up any open content
    jQuery(this.accordionContent).slideUp();
    // Remove any active classes
    jQuery(this.accordionTrigger).removeClass("active");
    // If the sibling content is hidden
    if(!jQuery(this.accordionTrigger).siblings().is(":visible")) {
        // slide it down
        jQuery(this.accordionTrigger).siblings().slideDown();
        // add a class to the title so we can style the active state and change the svg
        jQuery(this.accordionTrigger).addClass("active");
    }
}
}

    jQuery(document).ready(function ($){
       Accordion.init();
    });

The issue that I'm running into is with the way that 'this' works in Object Oriented Javascript. In the original setup, I was able to use 'this' to reference the accordion content that was clicked. I do not have access to that with the Object Oriented method. Can someone please help me out with?

Upvotes: 3

Views: 262

Answers (4)

Hieu Le
Hieu Le

Reputation: 728

Within toggleAccordion(), you can still use $(this) to get the accordion title element that has been clicked on. Hopefully then you can get the appropriate accordion content.

First bind it like how PHPglue mentioned:

jQuery(this.accordionTrigger).click(this.toggleAccordion);

Then you can do $(this) to get the accordionTitle:

toggleAccordion: function() {
    var $accordionTitle = $(this);
}

Basically when you bind it like that and the click is triggered, the scope changes and "this" is no longer "Accordion".

If you need to access accordionContent and accordionTrigger, you can either pass it into the function toggleAccordion or use Accordion.accordionContent and Accordion.accordionTrigger.

Additional source: http://api.jquery.com/click/#click-eventData-handler

Upvotes: 2

guest271314
guest271314

Reputation: 1

An alternative approach to @FelixKling solution, removing .bind() , using event.data to have access to both jQuery(this) and Accordion object within accordionTrigger handler

var Accordion = {
  accordionContent: '.accordion-container .accordion-content p',
  accordionTrigger: 'div',
  init: function() {
    // set `event.data` to `this`:`Accordion` at first parameter to `.click()`
    jQuery(this.accordionTrigger).click(this, this.toggleAccordion);
  },
  toggleAccordion: function(e) {
    // Slide up any open content
    // jQuery(e.data.accordionContent).slideUp();
    // Remove any active classes
    // jQuery(e.data.accordionTrigger).removeClass("active");
    // If the sibling content is hidden
    // `this`:`div`
    if (jQuery(this).is(e.data.accordionTrigger)) {
      console.log(this, e.data, $(e.data.accordionTrigger))
    }
  }
}
Accordion.init()
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<div>
  click
</div>

Upvotes: 2

David Gomez
David Gomez

Reputation: 2772

The problem is not how this works on OOP JavaScript because this is always referencing the caller object.

You can learn more about this with You Don't Know JS: this & Object Prototypes.

You can indeed use event.target and event.currentTarget as @Felix says, but eventually you will get into trouble if you don't understand how to use this properly or at least understand how it works.

Upvotes: 2

Felix Kling
Felix Kling

Reputation: 816442

You can use event.target to refer to the element that triggered the event, or event.currentTarget to refer to the element the handler was bound to, which is equivalent to using this.

toggleAccordion: function(event) {
    // Slide up any open content
    jQuery(this.accordionContent).slideUp();
    // Remove any active classes
    jQuery(this.accordionTrigger).removeClass("active");
    // If the sibling content is hidden
    if(!jQuery(event.currentTarget).siblings().is(":visible")) {
        // slide it down
        jQuery(event.currentTarget).siblings().slideDown();
        // add a class to the title so we can style the active state and change the svg
        jQuery(event.currentTarget).addClass("active");
    }
}

Learn more about event handling with jQuery.

Upvotes: 7

Related Questions