Passing object HTMLInputElement as a parameter to function - javascript

I am trying to pass a DOM element to a function without any luck. FireBug reports the following issue:
SyntaxError: missing ] after element list
LlenarDetalleReserva([object HTMLInputElement]); return false;
The selector needs to add a few attributes dynamically as it's being created.
I've tried the following:
$('#mySelector').attr({'onkeydown' : 'intOrFloat(event,this.value);', 'onchange' : 'LlenarDetalleReserva('+ $.trim($('#cant_r_'+ vectorid[2])[0]) +'); return false;'});
What am I missing here? What is producing this error?
Thanks in advance.

Please, don't do that. Use on() to bind an event to the element. Never set it as an attribute directly.
$('#mySelector')
.on('keydown', function(event)
{
intOrFloat(event, this.value);
})
.on('change', function(event)
{
if (vectorid && vectorid[2] != undefined)
{
var element = $('#cant_r_'+ vectorid[2]);
if (element.length > 0)
{
LlenarDetalleReserva(element);
}
}
return false;
});
The code above(full of ifs) is made to avoid exceptions at run-time. That is what I would do in your case. Further, I don't really know what you're trying to get in that $.trim() function, but it seems that you want to get the element and pass it as a string. In the code above its being passed by reference, instead.
UPDATE:
In order to answer OP's question of why I shouldn't set an attribute directly I didn't tell you you can't add an attribute directly but an event handler as attribute.I can't tell what happens in the backgrounds of the engine, so in fact, it works adding as attribute. But isn't a best practice and it's part of Unobtrusive approach.

Related

jQuery objects and elements

I know I've seen a beautifully straightforward answer to a similar question before, but I haven't been able to remember or locate it, so apologies in advance.
I'm not new to coding, but I've had no formal training with Javascript/jQuery. Everything else I used has been strictly typed, so I'm still struggling with how JS does typing. I have a function that fires every time a child of a specific class is changed (I'm writing this for Sharepoint, so there is some working-around that has to be done.)
Why is it when I write this:
$(".listen *").change(function(event) {
var element = event.target;
if (element.title == 'Workstation')) {
alert(element.val());
}
}
I get an error that .val() is not a function, and I have to instead write
$(".listen *").change(function(event) {
var element = event.target;
if (element.title == 'Workstation')) {
alert($('#' + element.id).val());
}
}
What is the difference between the object that "element" is and the object retrieved by using the id? Aren't they both jQuery objects? I realize that not all objects returned by my function might actually have a value to return, but I don't understand how the distinction is being made.
Thanks!
In your first code block the 'element' variable is not a jQuery object, it is a DOM object. The .val() method is not defined for DOM objects. It is only defined for jQuery objects.
In your second code block $('#' .element.id) returns a jQuery object that does have the val() method defined.
So to answer your question, No they are not both jQuery objects, only the second one is.
You must make jQuery object from your dom (event.target) like that;
$(".listen *").change(function(event) {
var element = $(event.target);
if (element.attr('title') == 'Workstation')) {
alert(element.val());
}
}
Then you can use your jQuery object as you want. By the way, if you want to catch the changed element, you can use $(this) instead of $(event.target).
$(".listen *").change(function(event) {
var element = $(this);
if (element.attr('title') == 'Workstation')) {
alert(element.val());
}
}

addEventListener() to non-existent elements?

I have attached a click event listener on an element like:
document.querySelector('.class-name').addEventListener('click', function () {
});
The element may or may not get generated from the server-side.
So, if the server generates the element then all works fine but if not then I get an error like:
Cannot read property 'addEventListener' of null
I know why this happens, but I want to know whether there is a better way of attaching event listeners to elements that won't generate such errors?
There's no way of doing this without some sort of conditional test, but you can save a few characters compared to an if block thus:
var el = document.querySelector('.class-name');
el && el.addEventListener(...);
I don't believe there's any simple way of avoiding the temporary variable (but see below).
NB: the below is included just to show that it's possible and should not be construed as a recommendation ;-)
If this is a very common pattern in your HTML and JS, a way to avoid the temporary assignment to el is this:
var missing = {
addEventListener: function() {};
}; // a "null" element
(document.querySelector('.className') || missing).addEventListener(...);
The idea being that the || missing ensures that there's something present to absorb the addEventListener reference and invocation.
Just check before if your element is here or not (like in comment ) :
var el = document.querySelector('.class-name');
if (el) { el.addEventListener(...); }
Edit : You can also wrap your element .class-name into a div and do something like that :
document.getElementById("myDiv").addEventListener("click",function(e) {
var classes = e.target.className;
if(classes = ".class-name")
//DO SOMETHING
});
Since ES2020
ES2020 introduced optional chaining and that feature is exactly what you need here:
document.querySelector('.class-name')?.addEventListener('click', ()=> console.log("Clicked"));
Supported in all modern up-to-date browsers.
You have to be sure that element exist. So
var element = document.querySelector('.class-name');
if (element)
element.addEventListener('click', function () {});

addEventListener to all but one element

I'm trying to wean myself off jQuery (my heart is in the right place, no?), and I'm having trouble getting to what would be the equivalent of the :not() selector.
I have document.body.addEventListener("mousewheel", scrollTriggered), which I want to fire on scroll of anything but a specific div (in the fiddle, #something). I've tried integrating event.target, to no avail.
Any help greatly appreciated.
See JSFiddle
You can check whether the event originated from within the element you want to avoid. To do that, you have to traverse up the DOM tree from target and compare each Node's id attribute, or use Node.contains (check the compatibility section first though):
var ignore = document.getElementById('something');
function scrollTriggered(event) {
var target = event.target;
if (target === ignore || ignore.contains(target)) {
return;
}
// do other stuff
}
DEMO
That said, Markasoftware's answer is even better, since it prevents the event in the first place.
The easiest way is probably to set an addEventListener with the third argument to false that does the action, and then have another addEventListener on the element you want to exclude, with a third argument true, which will cancel the event from propagating to the other event listener. The third argument is a little complicated, but the important part is that if it's set to true, that listener will fire before any false handlers. As #FelixKling said, you actually don't need it to be true here, but it's good practice to do it whenever you need a handler to fire before another one, because sometimes it IS needed. Here's a jsfiddle example: http://jsfiddle.net/markasoftware/sBg3a/2/
document.body.addEventListener("mousewheel", scrollTriggered,false);
function scrollTriggered() {
console.log('hi');
}
document.getElementById('something').addEventListener('mousewheel',function(e) {
e.stopPropagation();
}, true);
Although #FelixKling's answer works, I personally think this is more elegant and generally use things like this instead of the other way. I just like how you can have the main event listener just have the listener code, and all the stuff that cancels the event from propagating can be completely separate, making it more unobstrusive
You can check the target element inside your event handler and if that target element has id something return false;
something like this:
function scrollTriggered (event) {
if (event.target.id === "something") {
// don't do anything
return;
} else {
// do something
}
}
You will can use next example code with EcmaScript 6:
function scrollTriggered(event) {
var target = event.target;
if (target.outerHTML.includes('something')) {
return;
}
// do other stuff
}
We extract string from html element and try found in it something. This will work if you located inside necessary element which need ignore.

jQuery 1.9.1 property selector

Background
As of jQuery 1.9 the .attr(..) method no longer returns property values, instead we now have to use .prop(..). Unfortunately this also applies to attributes specified via an attributes selector i.e. $("input[value=]")
See
http://jquery.com/upgrade-guide/1.9/#attr-versus-prop-
and a good SO discussion on the differences between .attr and .prop :
.prop() vs .attr()
My Situation
I'm currently using selectors like $("input[value=]") and $("select[value=]")
to select input elements that have no value set. However, this no longer works with jQuery 1.9, instead I'm now doing something like this:
var hasValue = function () { return !!($(this).val().length); };
var hasNoValue = function () { return !($(this).val().length); };
$("input").filter(hasValue);
$("select").filter(hasValue);
My actual selectors are a little larger, checking multiple elements with or without values so now I'm having to split my 1 selector string into multiple selectors with .filter(..) method calls in between.
Question
Is there an equivalent to $("[value=]"), $("[value!=]"), $("[value='abc']") which uses the property instead of the attribute? And if not, is there a cleaner way than using the .filter(hasValue) and .filter(hasNoValue) methods?
Thanks
Using .filter seems to be the only way, but it's not too bad and you can actually make it a little more accurate by using .val:
$(":input").filter(function () { return $(this).val() === ""; });
If this really is that reprehensible to you, you could create a custom selector.
$.expr[':'].emptyInput = function (elem) {
return $(elem).is(":input") && $(elem).val() === "";
};
http://jsfiddle.net/ExplosionPIlls/zaZPp/
EDIT: You may also be able to get away with using this.value instead of $(elem).val().
According to the upgrade guide:
However, when a selector like "input[value=abc]" is used, it should always select by the value attribute and not any change made to the property by the user, for example from them typing into a text input. As of jQuery 1.9, this behaves correctly and consistently. Earlier versions of jQuery would sometimes use the property when they should have used the attribute.
So this answers your first question - there is not a direct equivalent, the point is to use the attribute instead of the property.
Your code seems fine, but if you want to be more standardized and re-usable you could create an additional filter. Like so:
(function($) {
$.expr[':'].hasValue = function(element) {
var $element = $(element);
return element.is(':input') && element.val();
};
}(window.jQuery));
This will allow you to select stuff like that:
// Select input elements with value and select elements without value.
$('input:hasValue,select:not(:hasValue)');
And other various combinations you need.
I came across this and just wanted to post another solution I found that works in some situations where some of the other suggested solutions are not appropriate.
Simply add this event handler to your code
$('input').on('keyup', function(){
var value = $(this).val();
$(this).attr('value', value);
});

Reset element to "default" event

In Javascript, how can you set the event handler of a DOM element to default behavior?
For example, suppose I set the onkeypress event of an input element:
elem.onkeypress = function() { alert("Key pressed!"); }
Later, how can I remove this event? Is it okay to simply set the onkeypress property to null? I tried that and it works, but I don't know if it is the proper way to do this.
I'm pretty sure that the events will be undefined rather than null, so you'd be better off setting back to that.
It's probably overkill, but to be more robust, you're arguably better off keeping a reference to whatever used to be registered to the onkeypress event & reassign that (just in case some other script is trying to use it too). So:
var oldKeyPress = elem.onkeypress;
elem.onkeypress = function() { alert("Key pressed!"); }
//... later ...
elem.onkeypress = oldKeyPress;

Categories