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?
CodePudding user response:
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.
CodePudding user response:
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 idid="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 data-goodness="cheers">
<div >
<div >We are happy to have:</div>
<label>First Name</label>
<input type="text" /><span ></span>
</div>
</div>
<div data-goodness="cheers">
<div >
<div >We are happy to have:</div>
<label>First Name</label>
<input type="text" /><span ></span>
</div>
</div>
</div>
<div data-goodness="cheers">
<div >
<div >OUT OF SCOPE</div>
<label>First Name</label>
<input type="text" /><span ></span>
</div>
</div>
CodePudding user response:
Try this
$('#first_name').on('input', (e) => {
let el = e.target;
const name = $(el).val();
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)
}
})