positional method instead of selector in jquery event

Viewed 135

I'm catching a custom event like this:

$("#my_div").on("custom_event", ".some_class:first", function...

That is working fine. The thing is that because jQuery 3.4 is deprecating :first selector (among others), I would like to do something like

$("#my_div").on("custom_event", $(".some_class").first(), function...

But that doesn't work because the selector parameter must be a string. In my case the event is captured on second, third, etc. besides the first one. I need to only be captured on first.

How can I update the code? I would like to avoid and if statement to test the position, is there a way to make it work like before?

4 Answers

First, that deprecation appears in the jQuery version 3.4.0 release notice dated of april 10th, 2019.

They say:

Anything you can do with positional selectors, you can do with positional methods instead. They perform better anyway.

Okay... Sadly, the documentation lacks an explanation on possible code replacement/upgrade about the use of this useful pseudo-selector in the delegation scenario you point out.

Now, that only is a deprecation... not a removal notice. So you don't actually have to upgrade your code for now. The latest jQuery version is 3.5.1 (may 4th, 2020) and there was no removal of :first and similar pseudo-selectors yet.

I guess that if you want to make it overkill anyway to be future-proof, this would give an equivalent result:

$("#my_div").on("custom_event", function(e){
  let $this = $(e.target).closest("#my_div").find(".some_class").eq(0)
  
  $this.doSomethingElseHere()
  //...
})

That is making the event handler attached to #my_div and $this being the delegated element.

I agree that's ugly! So I would not do that (lol). It's only is to point out there always will be another way to do it... And for now, that is the best I can think of considering what we have in the not yet deprecated toolset.

is there a way to make it work like before?

As of november 2020, you can use the latest jQuery version and use that :first pseudo-selector in delegation.

You can use ':first-child' instead.

$("#my_div .some_class:first-child").on("custom_event", function(){
   // code 
)};

if you are manipulating DOM (create elements dynamically) you just have to use .on() on something that is there from start, the selector will not change, for example:

$(document).on('custom_event', "#my_div .some_class:first-child",function(){
  // code
})

It makes sense that jquery changed it so it equaly matches the css pseudo-selectors.

Have you tried using the :first-of-type or :nth-child(1) selector? Because I believe that's what you're supposed to be doing.

EDIT

AS both :first() and :eq() will be deprecated, you could filter later.

$("#my_div").on("custom_event", ".some_class", function(e){
  var target = $(this).parent().children().first();
});

You may consider using .closest() and .find() in case they are not direct parent or child nodes.

$(function() {
  $(".container").on("click", ".item", function(e) {
    var target = $(this).closest(".container").find(".item").first();
    console.log(target.text());
  });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
  <div class="item">Item 1</div>
  <div class="item">Item 2</div>
  <div class="item">Item 3</div>
</div>

Related