0

I've been trying to figure this problem out for the last 2 days and have not found any solution so far.

Im trying to attach a .click() listener to all elements of a list, but any time I use this or $(this) none of the jquery functions work, for example using .val() returns undefined even though it has a value.

I'm using fomantic-ui but I've also tried the same code without and it doesn't work either. I'm also using NodeJS and Express, in case that makes a difference.

Further testing showed me that for some reason this doesn't work:

$('#first_name').on('input', () => {
    const name = $(this)
    const field = name.parent()

    if (!name.val().match(/^\p{L}{1,16}$/u)) {
        field.attr('class', 'field error')
        name.prop('valid', false)
    } else {
        field.attr('class', 'field success')
        name.prop('valid', true)
    }
})

But if I change it to this, everything is fine:

$('#first_name').on('input', () => {
    const name = $('#first_name') //Only Change...
    const field = name.parent()

    if (!name.val().match(/^\p{L}{1,16}$/u)) {
        field.attr('class', 'field error')
        name.prop('valid', false)
    } else {
        field.attr('class', 'field success')
        name.prop('valid', true)
    }
})

And also this both return false

console.log($(this) === $('#first_name'), $(this) == $('#first_name'))
//false false

I have tried all sorts of combinations but nothing I can think of works, and nothing I found anywhere online has either. Maybe I just don't understand how this is supposed to work but I've tried reading the jquery documentation but it didn't help me.

Can anyone help me?

3
  • 2
    => functions are not like traditional functions in at least one way that makes a huge difference with jQuery code. Commented Apr 12, 2022 at 19:21
  • Please show your HTML for at least two (or your list "wrapper" html since $('#first_name') seems to indicate you may have duplicates in your "list" perhaps; and your name.parent() feels like it might be better written - this is really outside the question scope but we may be able to give you perhaps a better event handler here given your "list" statement Commented Apr 12, 2022 at 19:33
  • Question because I am curious why 'input' and not 'change'? Commented Apr 12, 2022 at 19:35

2 Answers 2

2

You're using an arrow function, so the value of this will be inherited from the parent context. A console.log should show you what that is.

You probably want to use a regular anonymous function, assuming jQuery calls the function with the HTML element set to the context of this.

$('#first_name').on('input', function() {
   // ...
});

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions

Arrow functions don't have their own bindings to this or super, and should not be used as methods.

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

Comments

1

Here I have an example where I use a class instead of an id on the input group.

  • Your scope issue is resolved by using function(event){ form for the function
  • I use the .closest('.wrapper') to get the "owner" of the group.
  • I hooked the event handler using the container ID: $('#inputs-container')
  • I use a data attribute and set a value for that to do some "creative" css depending upon the condition
  • IF for some reason you need to get the container, you can use the event.delegateTarget - this is the container element with the id id="inputs-container"
  • I added the change event also in case someone does a "paste" or you change the value programmatically
  • I would suggest you use semi-colons on the ends of the lines in the script; at some point not doing so will cause a very hard to find bug

I admit this is a bit of overkill but perhaps someone can get some use of the example even though it is admittedly a bit "verbose". Try it out by entering in text, numbers and spaces in each of the three inputs.

$('#inputs-container').on('input change', '.first-name',function(event) {
  const $input = $(this);
  const field = $input.closest('.wrapper');
  //console.log(field.data('goodness'), field.get(0).dataset);
  let val = $input.val();
  const regex = /^\p{L}{1,16}$/u;
  const isGood = val.match(regex) == val;
  //console.log('Good:', val, isGood);
  field.get(0).dataset.goodness = isGood ? "success" : "error";
  $input.prop('valid', isGood);
});
.wrapper {
  border: 1px solid #d0d0d0;
  border-width: 0.5em;
  padding: 0.5em;
}

.wrapper[data-goodness="error"] {
  border-color: #FF0000;
  border-width: 0.5em;
}

.wrapper[data-goodness="error"] .err-message:before {
  content: "Do Better";
  padding-left: 1em;
}

.wrapper[data-goodness="success"] {
  border-color: #00FFdd;
}

.wrapper[data-goodness="success"] .err-message:before {
  content: "Doing well so far!";
  padding-left: 1em;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="inputs-container">
  <div class="wrapper" data-goodness="cheers">
    <div class="field-things">
      <div class="field-name-thing">We are happy to have:</div>
      <label>First Name</label>
      <input type="text" class="first-name" /><span class="err-message"></span>
    </div>
  </div>
  <div class="wrapper" data-goodness="cheers">
    <div class="field-things">
      <div class="field-name-thing">We are happy to have:</div>
      <label>First Name</label>
      <input type="text" class="first-name" /><span class="err-message"></span>
    </div>
  </div>
</div>
<div class="wrapper" data-goodness="cheers">
  <div class="field-things">
    <div class="field-name-thing">OUT OF SCOPE</div>
    <label>First Name</label>
    <input type="text" class="first-name" /><span class="err-message"></span>
  </div>
</div>

Comments

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.