3

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?

2
  • 1
    Why bind to this? It already is. Commented Sep 21, 2015 at 1:43
  • @PHPglue thanks for the response. I'm sorry but I'm not sure what you mean. My issue is inside the if statement...in the original function, i could use 'this' to target the specific accordion that was clicked on. In the object, I cannot use that method. Were you referencing the 'bind' in the init function? Commented Sep 21, 2015 at 1:48

4 Answers 4

7

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, Felix. Can you show me exactly how/where I would use that?
2

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.

1 Comment

Thanks, Dave. I am checking this out now
2

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>

Comments

2

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

3 Comments

How to access this.accordionContent and this.accordionTrigger then?
Ah i see, yeah definitely read up on this. So what you have to do is either pass it in or just access it using "Accordion.accordionContent" and "Accordion.accordionTrigger"
It's not my question... you should include that in your answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.