Value is undefined when element is obtained with jQuery - javascript

Below is the code where I obtain my input element with jQuery:
var txt = $(tableRow).find('input:text');
if (txt.value == null) {
//TO DO code
}
and here's how I do it with pure JavaScript
var txt = document.getElementById('txtAge');
if (txt.value == null) {
//TO DO code
}
With the first way the value of the txt is undefined. But with the second way the value is what's inside the input element. Now more interesting is, on the bottom-right pane of the Mozilla Firebug if I scroll down to the "value" of the txt I can see it there, both ways.
I know I can simply say $(txt).val(), but I also want to understand why I can't access the value of an element if it's been selected by jQuery. Isn't jQuery just a library of JavaScript functions?

.value is not part of the jquery api. You should use .val() instead:
var txt = $(tableRow).find('input:text');
if (txt.val() == "") {
//TO DO code
}
A dom object and a jquery dom object are not exactly the same. In fact, you can open the Developer tools (in webkit) or Firebug (Firefox) to check what are they in the inside. Jquery holds more information (actually, it contains an instance of the dom that it's representing). So, if you wanted to use .value, you need to call the "generic" dom object from the jquery object, and then use .value.

jQuery selects DOM elements using various native and non-native techniques and places them all in it’s own array-like instance that also wraps them in their own API. jQuery doesn’t "extend" native DOM properties or methods, so you will need to target the DOM node to do that.
Think of it like this:
var node = document.getElementById('txtAge'); // the DOM node
var txt = $('#txtAge'); // the same node wrapped in a jQuery object/API
Since jQuery object holds an array-like collection of DOM nodes, so you can access the first element by doing:
txt[0] // same as node
But it’s generally recommended that you use the .get() method:
txt.get(0)
Another more jQuery-way to do what you want is to iterate through a jQuery collection using .each():
$(tableRow).find('input:text').each(function() {
// "this" in the each callback is the DOM node
if ( this.value == null ) {
// Do something
}
});

.find() will return an arry-like object. If you're sure that there's one, and one only, element matching your query, you could do
var txt = $(tableRow).find('input:text')[0].value;
That's not very jQuery-like, so to speak, more like a mismatch of both jQuery and DOM methods, but it'll get what you want. Also, since you show, as a DOM example, var txt = document.getElementById('txtAge');, this could be rewritten in jQuery as
var txt = $('#txtAge')[0];

var x = $(tableRow).find('input:text');
It's an jquery object .
`x.value`
There is no property value in jquery object . So it returns undefined.
x.val() is a method you can use for get the value of an element.

Related

jQuery throws an error that element.find() is not a function

I have written a small JS to iterate through a set of matched elements and perform some task on each of them.
Here is the code:
var eachProduct = $(".item");
eachProduct.each(function(index, element){
var eachProductContent = element.find(".product-meta").clone();
});
When I console log element it outputs properly and the exact objects. Why should jquery throw this error?
because element is a dom element not a jQuery object
var eachProductContent = $(element).find(".product-meta").clone();
Inside the each() handler you will get the dom element reference as the second parameter, not a jQuery object reference. So if you want to access any jQuery methods on the element then you need to get the elements jQuery wrapper object.
You are calling .find() on a plain JS object, But that function belongs to Jquery object
var eachProductContent = $(element).find(".product-meta").clone();
You can convert it to a jquery object by wrapping it inside $(). And in order to avoid this kind of discrepancies you can simply use $(this) reference instead of using other.
Use $(this) for current Element
var eachProductContent = $(this).find(".product-meta").clone();
you should change "element" to "this":
var eachProduct = $(".item");
eachProduct.each(function(index, element){
var eachProductContent = $(this).find(".product-meta").clone();
});

jQuery.find() returns an object even when there's no matching child element in the DOM

I am trying to find an element with the ID '' that is within the element '', and therefore is its child.
I am using the $.find method to perform the search.
If the child object is found, I'd like to perform some actions, and if the child object isn't found, I'd like to do different things.
However, even though I know that there is no such child element existing, the jQuery.find method reports an object that I am not sure, from inspecting in the Watches window, what it is.
Here's the relevant code snippet:
function CreateResourceKeyTextBox(resourceKeyId, editMode) {
var resourceKeyTableCell = $("#tdKeyResourceKeyId" + resourceKeyId);
var resourceKeyNameTextBox = null;
var alreadyExistingResourceKeyNameTextBox = resourceKeyTableCell.find('#txtResourceKeyName' + resourceKeyId);
if (alreadyExistingResourceKeyNameTextBox != null && typeof alreadyExistingResourceKeyNameTextBox != "undefined") {
resourceKeyTableCell.html('');
resourceKeyNameTextBox = alreadyExistingResourceKeyNameTextBox;
resourceKeyNameTextBox.css('display', 'block');
resourceKeyNameTextBox.appendTo('#tdKeyResourceKeyId' + resourceKeyId);
resourceKeyNameTextBox.css('width', '96%');
}
jQuery query functions always return an object, even if there's no matching DOM elements.
Check the length, it will be 0 if there's no element in the set :
if (alreadyExistingResourceKeyNameTextBox.length ...
jquery's find method returns a jquery object whose internal matched elements are the corresponding elements to your css selector.
If css selector fails to match any elements, then, jquery's find method's return object's internal matched elements is an empty array. You can get internal matched elements with .get method as follows:
var elems = $.find(css_selector).get()
this method returns array of DOM elements not jquery object instances, and you can check empty array using following syntax
var elems = $.find(css_selector).get()
if(elems.length === 0){
//array is empty
}else{
//array is not empty
}
This behaviour of jquery minimizes any syntax errors you might get otherwise, jquery will work without errors, no matter your css selector matches any DOM elements or not. This is beneficial in most cases, where you simply apply some changes on matched elements regardless of there are any. If existence of such elements is critical to your business logic, you should check it manually.
You should use alreadyExistingResourceKeyNameTextBox.length != 0 instead I think
if an object is not found using jquery .find() method, it always return an empty array. if you are getting anything other than that, you need to check your DOM. You can always check the length of the result i.e. result.length > 0 || result.length === 1, depending on your need

jQuery append() vs appendChild()

Here's some sample code:
function addTextNode(){
var newtext = document.createTextNode(" Some text added dynamically. ");
var para = document.getElementById("p1");
para.appendChild(newtext);
$("#p1").append("HI");
}
<div style="border: 1px solid red">
<p id="p1">First line of paragraph.<br /></p>
</div>
What is the difference between append() and appendChild()?
Any real time scenarios?
The main difference is that appendChild is a DOM method and append is a jQuery method. The second one uses the first as you can see on jQuery source code
append: function() {
return this.domManip(arguments, true, function( elem ) {
if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
this.appendChild( elem );
}
});
},
If you're using jQuery library on your project, you'll be safe always using append when adding elements to the page.
No longer
now append is a method in JavaScript
MDN documentation on append method
Quoting MDN
The ParentNode.append method inserts a set of Node objects or DOMString objects after the last child of the ParentNode. DOMString objects are inserted as equivalent Text nodes.
This is not supported by IE and Edge but supported by Chrome(54+), Firefox(49+) and Opera(39+).
The JavaScript's append is similar to jQuery's append.
You can pass multiple arguments.
var elm = document.getElementById('div1');
elm.append(document.createElement('p'),document.createElement('span'),document.createElement('div'));
console.log(elm.innerHTML);
<div id="div1"></div>
append is a jQuery method to append some content or HTML to an element.
$('#example').append('Some text or HTML');
appendChild is a pure DOM method for adding a child element.
document.getElementById('example').appendChild(newElement);
I know this is an old and answered question and I'm not looking for votes I just want to add an extra little thing that I think might help newcomers.
yes appendChild is a DOM method and append is JQuery method but practically the key difference is that appendChild takes a node as a parameter by that I mean if you want to add an empty paragraph to the DOM you need to create that p element first
var p = document.createElement('p')
then you can add it to the DOM whereas JQuery append creates that node for you and adds it to the DOM right away whether it's a text element or an html element
or a combination!
$('p').append('<span> I have been appended </span>');
appendChild is a DOM vanilla-js function.
append is a jQuery function.
They each have their own quirks.
The JavaScript appendchild method can be use to append an item to another element. The jQuery Append element does the same work but certainly in less number of lines:
Let us take an example to Append an item in a list:
a) With JavaScript
var n= document.createElement("LI"); // Create a <li> node
var tn = document.createTextNode("JavaScript"); // Create a text node
n.appendChild(tn); // Append the text to <li>
document.getElementById("myList").appendChild(n);
b) With jQuery
$("#myList").append("<li>jQuery</li>")
appendChild is a pure javascript method where as append is a jQuery method.
I thought there is some confusion here so I'm going to clarify it.
Both 'append' and 'appendChild' are now native Javascript functions and can be used concurrently.
For example:
let parent_div = document.querySelector('.hobbies');
let list_item = document.createElement('li');
list_item.style.color = 'red';
list_item.innerText = "Javascript added me here"
//running either one of these functions yield same result
const append_element = parent_div.append(list_item);
const append_child_element = parent_div.appendChild(list_item);
However, the key difference is the return value
e.g
console.log(append_element) //returns undefined
whereas,
console.log(append_child_element) // returns 'li' node
Hence, the return value of append_child method can be used to store it in a variable and use it later, whereas, append is use and throw (anonymous) function by nature.

Retrieving an element by array index in jQuery vs the each() function

I was writing a "pluginable" function when I noticed the following behavior (tested in FF 3.5.9 with Firebug 1.5.3).
$.fn.computerMove = function () {
var board = $(this);
var emptySquares = board.find('div.clickable');
var randPosition = Math.floor(Math.random() * emptySquares.length);
emptySquares.each(function (index) {
if (index === randPosition) {
// logs a jQuery object
console.log($(this));
}
});
target = emptySquares[randPosition];
// logs a non-jQuery object
console.log(target);
// throws error: attr() not a function for target
board.placeMark({'position' : target.attr('id')});
}
I noticed the problem when the script threw an error at target.attr('id') (attr not a function). When I checked the log, I noticed that the output (in Firebug) for target was:
<div style="width: 97px; height: 97px;" class="square clickable" id="8"></div>
If I output $(target), or $(this) from the each() function, I get a nice jQuery object:
[ div#8.square ]
Now here comes my question: why does this happen, considering that find() seems to return an array of jQuery objects? Why do I have to do $() to target all over again?
[div#0.square, div#1.square, div#2.square, div#3.square, div#4.square, div#5.square, div#6.square, div#7.square, div#8.square]
Just a curiosity :).
.find() returns not an array of jQuery objects, but one jQuery object containing an array of DOM elements (a jQuery object, at it's core, is a wrapper around a DOM element array).
When you're iterating through, each element you're on is a DOM element. So, it needs to be wrapped in $(this) to become jQuery object and have access to those methods.
Also as a side note: The id attribute can't begin with a number, since it's invalid HTML you may or may not experience strange behavior, especially cross-browser (this rule applies for any invalid HTML).
No, the find method doesn't return an array of jQuery objects. You are creating a jQuery object for each element here:
console.log($(this));
If you log the value without creating a jQuery object from it:
console.log(this);
you will see that it's an element, not a jQuery object.
When you access the jQuery object as an array, you get an element. If you want a jQuery object you have to create one from the element.

Setting properties on anonymous DOM elements through JavaScript?

Let's say I'm generating markup through server-side code. I'm generating a bunch of HTML tags but I want to add custom client-side behavior.
With JavaScript (if I had a reference to the DOM node) I could have written:
var myDOMNode = ...
myDOMNode.myCustomAttribute = "Hi!";
Now the issue here is that I don't want to qualify every element with an unique id just to initialize data. And it's really strange to me, that there's not an easier and unobtrusive way to attach client-side behavior.
If I'm remembing this correctly, this is valid IE stuff.
<div onload="this.myCustomAttribute='Hi!'"></div>
If I was able to do this, I should be able to access it's "data context" though the identifier 'myCustomAttribute', which is really what I want.
The following will work but not validate:
<div myattribute="myvalue"></div>
But if you are injecting it into the HTML with Javascript, then perhaps that's not concern for you. Otherwise, you can use something like jQuery to process the elements before adding them to the DOM:
$(elements).each(function(){
$(this).attr('myattribute','myvalue');
});
First off you should access custom attributes using the getAttribute and setAttribute methods if you want your code to work on other browsers than IE.
As to your event handler question that really depends on how you add the event handler.
Assigning a function directly to the elements onXXXX property would allow you access the the element via this.
If you use IE's attachEvent you can't use this, you can access the element that generated the event using event.srcElementbut that may be child element of the div. Hence you will need to test for the existance of myCustomAttribute and search up the ancestors until you find it.
I do appricate the input but I've finally figured this out and it's the way I go about initialization that has been the thorn in my side.
What you never wan't do is to pollute your global namespace with a bunch of short lived identifiers. Any time you put id="" on an element you're doing exactly that (same thing for any top level function). By relying on jQuery, HTML5 data and CSS there's a solution to my problem which I think is quite elegant.
What I do is that I reserve a CSS class for a specific behavior and then use HTML5 data to parameterize the behavior. When the document is ready, I query the document (using Query) for the CSS class that represents the behavior and initialize the client-side behavior.
I've been doing a lot of ASP.NET and within this context both the id="" and name="" belongs to ASP.NET and is pretty useless for anything else than internal ASP.NET stuff. What you typically find yourself doing is to get at a server-side property called ClientID you can refer to this from client-side JavaScript, it's a lot of hassle. They made it easier in 4.0 but fundamentally I think it's pretty much broken.
Using this hybrid of CSS, HTML5 data and jQuery solves this problem altogether. Here's an example of an attached behavior that uses regular expressions to validate the input of a textbox.
<input type="text" class="-input-regex" data-regex="^[a-z]+$" />
And here's the script:
$(function () {
function checkRegex(inp) {
if (inp.data("regex").test(inp.val()))
inp.data("good-value", inp.val());
else
inp.val(inp.data("good-value"));
}
$(".-input-regex")
.each(function () {
// starting with jQuery 1.5
// you can get at HTML5 data like this
var inp = $(this);
var pattern = inp.data("regex");
inp.data("regex", new RegExp(pattern));
checkRegex(inp);
})
.keyup(function (e) {
checkRegex($(this));
})
.change(function (e) {
checkRegex($(this));
})
.bind("paste", undefined, function (e) {
checkRegex($(this));
})
;
});
Totally clean, no funky id="" or obtrusive dependency.
In HTML5 there are HTML5 data attributes introduced exactly for the case.
<!DOCTYPE html>
<div data-my-custom-attribute='Hi!'></div>
is now corect, validating html. You can use any name starting with data- in any quantity.
There is jQuery .data method for interaction with them. Use .data( key ) to get, .data(key, value) to set data-key attribute. For example,
$('div').each(function () {
$(this).html($(this).data('myCustomAttribute')).data('processed', 'OK');
});
How about this?
<script>
function LoadElement(myDiv)
{
alert(this.myCustomAttribute);
}
</script>
<div onload="LoadElement(this)"></div>
not tested btw
Since you're trying to do this for multiple elements, you may try name attributes and getElementsByName.
<div name="handleonload">...</div>
window.onload = function () {
var divs = document.getElementsByName('handleonload');
for (var i = 0; i < divs.length; i += 1) {
divs[i].foo = 'bar';
}
};
Alternatively, you can use selectors, using libraries (such as jQuery and Prototype) and their respective iterators. This will also allow for you to search by other attributes (such as class).
Though, be cautious with your terminology:
obj.property = value;
<tag attribute="value">
<div style="width:100px;height:100px;border:solid black 1px" myCustomAttribute='Hi!' onclick="alert(myCustomAttribute);"></div>
The onload event is used for server side events. Its not part of the standard html element events.
Take a look at the following functions (especially the walk_the_dom one):
// walk_the_DOM visits every node of the tree in HTML source order, starting
// from some given node. It invokes a function,
// passing it each node in turn. walk_the_DOM calls
// itself to process each of the child nodes.
var walk_the_DOM = function walk(node, func) {
func(node);
node = node.firstChild;
while (node) {
walk(node, func);
node = node.nextSibling;
}
};
// getElementsByAttribute takes an attribute name string and an optional
// matching value. It calls walk_the_DOM, passing it a
// function that looks for an attribute name in the
// node. The matching nodes are accumulated in a
// results array.
var getElementsByAttribute = function (att, value) {
var results = [];
walk_the_DOM(document.body, function (node) {
var actual = node.nodeType === 1 && node.getAttribute(att);
if (typeof actual === 'string' &&
(actual === value || typeof value !== 'string')) {
results.push(node);
}
});
return results;
};
With the above two functions at hand, now we can do something like this:
some link
<script>
var els = getElementsByAttribute('dreas');
if (els.length > 0) {
els[0].innerHTML = 'changed text';
}
</script>
Notice how now I am making finding that particular element (which has an attribute called dreas) without using an id or a class name...or even a tag name
Looks like jQuery is the best bet for this one based on my searching. You can bind an object to a DOM node by:
var domNode = ...
var myObject = { ... }
$(domNode).data('mydata', mymyObj);
then you can call the data back up the same way, using your key.
var myObect = $(domNode).data('mydata');
I assume you could also store a reference to this within this object, but that may be more info then you really want. Hope I could help.

Categories

Resources