Forums

The forums ran from 2008-2020 and are now closed and viewable here as an archive.

Home Forums JavaScript Why is 'this' not the jQuery selector?

  • This topic is empty.
Viewing 15 posts - 1 through 15 (of 15 total)
  • Author
    Posts
  • #203539
    Shikkediel
    Participant

    Working on this page scrolling plugin that pretty straightforward :

    $(document).ready(function() {
    
      $(this).impulse();
    })
    

    That’ll create a full page effect…
    It can also be used on descendant elements :

    $(document).ready(function() {
    
      $('#element').impulse();
    })
    

    Scrolling only some segment of the page…
    One of the options is to set the amount to be scrolled – here’s is where something I don’t get comes in. This works :

    $(document).ready(function() {
    
      $('#element').impulse(range: $('#element').height());
    })
    

    And I would have expected for this to get the same result :

    $(document).ready(function() {
    
      $('#element').impulse(range: $(this).height());
    })
    

    But it doesn’t. Instead $(this) seems to refer to whatever object the wrapping function is, so in this case it would return the height of the document. And with this you get the screen height :

    $(window).on('load', function() {
    
      $('#element').impulse(range: $(this).height());
    });
    

    Anyone have a clue why it might be ‘skipping’ the direct object the method was applied to? Not getting this one at all.

    Some examples can be found here (starting to get quite nifty for the rest, still working on the documentation) :

    http://ataredo.com/morphology/lucidscroll/

    #203550
    Shikkediel
    Participant

    All I could find on it, which doesn’t really provide a good explanation…

    http://stackoverflow.com/questions/3453589/this-in-plugin-options

    #203559
    Alen
    Participant

    Try

    $(document).ready(function() {
      var $document = $(this);
      $('#element').impulse(range: $document.height());
    });
    
    #203562
    Ilan Firsov
    Participant

    Not really sure I understand what you are trying to do, but try

    $(document).ready(function() {
      var $element = $('#element');
      $element.impulse(range: $element.height());
    });
    

    or

    $(document).ready(function() {
      (function(){
        this.impulse(range: this.height());
      }).call($('#element'));
    });
    
    #203580
    Shikkediel
    Participant

    Thanks for the replies, guys.

    Alen, the odd thing is that the range property takes on the height of document even if you pass $(this).height() to it. So instead of this referring to the element that was selected with the method, it skips that level and automatically refers to whatever function the plugin was wrapped in.

    If you use this.height() inside the plugin itself, you get the height of the selected element like one would expect…

    Ilan, that does indeed work – I added something similar to the first snippet to the examples on the documentation page I’m writing about it. But it seems strange and unnatural that you can’t just use $(this) in the ‘usual’ way. Not seeing the inner logic of that (yet anyway)…

    #203616
    Anonymous
    Inactive

    But it seems strange and unnatural that you can’t just use $(this) in the ‘usual’ way. Not seeing the inner logic of that (yet anyway)…

    I’m not a javascript guru, so I may have this way off, but as far as I can tell from the documentation, this within an event handler refers to the element from which it fired. In the context of:

    $(document).ready(function() {
      $('#element').impulse(range: $(this).height());
    })
    

    That would be document, no?

    I’m not sure exactly what you mean by “in the usual way” but I’m pretty sure @ilanf is using it in the usual way.

    #203617
    Shikkediel
    Participant

    Thanks for the brainstorm. The event would be mousewheeling though, done in the context of $('#element') and it’s shouldn’t be bubbling up (because of stopPropagation() being used inside the plugin).

    It’s not the biggest deal getting it to work but I’m just never satisfied until I understand why something is happening…
    Function scope is a tricky one and I’m obviously not yet fully getting it.

    :-D

    What I meant with ‘the usual way’ is that for example with .animate you can refer to the selected element from within some options :

    $('#element').animate({scrollTop: somewhere}, {
    
    start: function() {$(this).dosomething()},
    
    ...
    
    });
    

    If dosomething() is getting the height for example, it will be that of #element… but it does have a function wrapped around it so that may be of influence. I’m sure I’ll figure it out at some point by means of experiment. Most tutorials on jQuery plugins don’t dig too deep unfortunately.

    #203629
    Shikkediel
    Participant

    Cheers, that seems helpful from the start already (although the beginning is something I should ‘know’, it’s still enlightening to read back when explained well). I’ll have a good read-through, much like this page deserves :

    http://api.jquery.com/jQuery.extend/

    #203640
    Anonymous
    Inactive

    What I meant with ‘the usual way’ is that for example with .animate you can refer to the selected element from within some options

    Not really. There’s a difference between your two examples. In your impulse example, you use this in the current context to define a variable. In the animate example you write a function that includes this. In the function context, this will mean whatever it ought to mean at the point at which the function is called.

    #203642
    Shikkediel
    Participant

    Seems to work when you set a variable/property directly as well though (duration would be the only option that doesn’t involve a function) :

    $('#element').animate({scrollTop: somewhere}, {
    
    duration: $(this).height(),
    
    ...
    
    });
    

    B-/

    Thanks for thinking along in any case…

    #203667
    Anonymous
    Inactive

    Thanks for thinking along in any case…

    That’s fine. It’s a slightly quirky topic, so kinda interesting.

    Does it not matter that in the final example you are within an object context (ie. {variable: this}) whereas in your first example you are not (ie. variable: this)?

    #203672
    Shikkediel
    Participant

    Good one, those are actually typos I hadn’t noticed in the first post.
    They should also be wrapped in an object extension :

    $(document).ready(function() {
    
      $('#element').impulse({range: $('#element').height()});
    });
    

    Sorry for the blooper (nice catch, must have been mystifying the issue).

    :-S

    I do believe your post is the crux of it though, I was thinking I was extending the jQuery object with these additional properties but somehow that must not be the case – when approaching it from the ‘outside’. Inside the plugin the selected element(s) will refer to this. The general way to do this :

    $.fn.impulse = function(options) {
    
        var set = $.extend({
    
          range: 135
        }, options);
    
    ...
    
    };
    

    If I do range: this and log set.range it’ll show an object with the elements that were selected with $(' ... ')

    Currently reading up on this, pretty interesting :

    Smashing Magazine article

    #203677
    Shikkediel
    Participant

    How can I forget to add the pen where the issue could be replicated rather easily…

    http://codepen.io/Shikkediel/pen/GJRbOV

    Somehow embedding doesn’t quite work with an external script. :-(

    #203727
    Shikkediel
    Participant

    Haven’t completely figured it out yet but I did discover something. When adding another option (a function this time) and logging ‘this’ through the method, it seems to refer to the var set itself :

    $.fn.impulse = function(options) {
    
        var set = $.extend({
    
          test: function() {}
        }, options);
    
        set.test();
    
    ...
    
    };
    
    $('element').impulse({
    
        test: function() {console.log(this)}
    });
    

    So that object (set) will extend to the selected elements from the ‘inner’ perspective of the plugin but it is not owned by them when applying the method. Since set isn’t a DOM element, getting the height obviously doesn’t lead anywhere…

    Comparing it to .animate() doesn’t seem fair. After looking at the jQuery source, any variables/properties are undergoing more operations so it’s not as straightforward as this issue.

    #203928
    Shikkediel
    Participant

    Thinking about it some more, it might be what jQuery is essentially about. Allowing access to the global object inside a plugin but keeping the variables private…

Viewing 15 posts - 1 through 15 (of 15 total)
  • The forum ‘JavaScript’ is closed to new topics and replies.