1

I was trying to add the functionality of toggleImage in a gallery and checked this thread and the code provided in one of the answers, but got Uncaught TypeError: Cannot read property 'attr' of undefined in the console.

HTML:

<div id="gallery">
   <figure>
     <img data-src="/assets/images/small/one.jpg">
     <a data-href="/assets/images/one.jpg">
   </figure>
   <figure>
     <img data-src="/assets/images/small/two.jpg">
     <a data-href="/assets/images/two.jpg">
   </figure>
   <figure>
     <img data-src="/assets/images/small/three.jpg">
     <a data-href="/assets/images/three.jpg">
   </figure>
</div>

  <div class="modal">
    <div class="">
      <img class="modal__image" src="">
    </div>
    <div class="modal__close">X</div>
  </div>

JavaScript that works:

import $ from 'jquery'

class ToggleImage {
  constructor() {
    this.thumbnail = $('#gallery img')
    this.modalImage = $('.modal__image')
    this.passHref()
  }

  passHref() {
    this.thumbnail.click(e => {
      const href = $(e.target).siblings().attr('data-href')
      this.modalImage.attr('src', href)
      e.preventDefault
      return false
    })
  }  
}

const toggleImage = new ToggleImage()

As you can see, var href = $(this) was changed to $(e.target).siblings(). Before this change I'd tried to use just this or just e.target with getAttribute() and non-arrow function, or add const that = this before line const href and use that instead, but none of them worked. May I know why?

And, so far the click event is bundled with the action code. But because I hope to separate the action from the event, $(e.target) doesn't fit in this case.

class ToggleImage {
  constructor() {
    this.thumbnail = $('#gallery img')
    this.modalImage = $('.modal__image')
    this.passHref()
    this.event()   // added
  }

  event() {
    this.thumbnail.click(this.passHref)
  }

  passHref() {
     // some code other than $(e.target)...
  }  
}
Community
  • 1
  • 1
sijane
  • 99
  • 6
  • 1
    `this` and `e.target` are Element objects, hence do not have a `siblings()` method. Therefore you need to use either `$(this)` or `$(e.target)` - preferably the former - to place those Elements within a jQuery object to be able to call jQuery methods on them. – Rory McCrossan Apr 19 '17 at 14:49
  • 2
    Your use of an arrow function is directly blocking what you want to do. – loganfsmyth Apr 19 '17 at 15:14
  • Related: [Arrow function vs function declaration / expressions: Are they equivalent / exchangeable?](http://stackoverflow.com/q/34361379/218196) – Felix Kling Apr 19 '17 at 15:51
  • @RoryMcCrossan `this.thumbnail.click(function(e) { const href = $(this).attr('data-href'); console.log(href); }` would be `undefined`. May I know what's the jQuery methods you mentioned here? If change `this.thumbnail = $('#gallery img')` to `this.thumbnail = $('#gallery figure')` as well. – sijane Apr 20 '17 at 01:05

2 Answers2

1

To further clarify the comments, here you can see how this works inside both a normal function and an arrow function.

console.log('global scope this: ' + this);

$('button').click(e => console.log('arrow function this: ' + this));

$('button').click(function(e) { 
  console.log('function this: ' + this); 
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>Click me</button>

Just to clarify, this in an arrow function will be the same as this outside the arrow function. In the code above the parent scope is global, where this is undefined.

mikeapr4
  • 2,830
  • 16
  • 24
  • The thing is when it was normal function, `const href = this.getAttribute('data-href')` would be `null` and `this.modalImage` would be `undefined` and that's why in the post I said non-arrow function didn't work either. – sijane Apr 20 '17 at 00:38
  • I'd suggest you continue with the solution you have, use an arrow-function and `e.target` - you have a working solution, your question was why. – mikeapr4 Apr 20 '17 at 12:34
1

in your component,'this' is the Object of 'ToggleImage'. you can't use $(this) because here js understands '$(this)' as '$(ToggleImage)'

dandanbu2
  • 31
  • 2