jQuery ID Selector ("#id") Returns Array - javascript

I'm using jQuery v1.6.1 in noConflict mode.
I'm using id selectors such as $j("#divID").value to get values of stored items.
Unfortunately, $j("#inputID") is returning a list of items, so I have to use the $j("divID")[0].value to get the value of the object. The [0] seems unnecessary, since there is, by definition, only one html element with any given id.
Is this the appropriate way to gets values from an IDed object? Or is there a better way?
Thanks!

$j("#divID").val() will work just fine.
Per the jQuery documentation, .val() will return the value of the first element in the set of matched elements.
It's worthwhile understanding conceptually how jQuery works in order to see why it works this way. The result of any selector query is a jQuery object. It's that jQuery object that contains the myriad of methods that jQuery offers. .val() is one of those methods as are things like .fadeIn(), .hide(), etc... Those methods are not methods on a DOM object, but methods of a jQuery object. Because jQuery objects are general purpose and can hold 0, 1 or more DOM objects in their internal array, you get the same jQuery object back from a jQuery selector call whether the results have 0, 1 or more DOM objects in it.
Thus $j("#divID") that contains only one object returns the same type of object as $j(".rows") which might contain hundreds of DOM objects. This vastly simplifies jQuery programming because you don't have to do things differently depending upon how many objects come back from the selector query.
When you refer to $j("divID")[0], you are reaching into the jQuery object's internal array of DOM objects (that was populated on the selector query) and fetching the first DOM object in that array. At that point, you have a normal DOM object, not a jQuery object and you can use normal DOM methods or attributes on it. Occasionally this is required (to fetch the actual DOM object), but usually, it's easier to just use the methods that jQuery provides on the jQuery object. There are lots of advantages to using them such as you can chain multiple requests to most methods and it will iterate over all the DOM objects in it's internal array for you automatically.
For example, you you called this: $j("rows-even").hide() and there were 20 rows with that class, then all of them would each be operated on by the hide() method with no more code than this. Of you could chain multiple methods together like this: $j("rows-even").slideUp().slideDown(). In this case, you're running an animation and jQuery will chain these two animations together, automatically starting the second one when the first one finishes. It's all pretty useful in many circumstances and can save a ton of code over what would normally have to be written using plain JS.

$j("#divID") returns a jQuery object. In order to get the value of the selected element you have to call its val method to get the value.
Use $j("#divID").val();

Related

Instantiating Objects Dynamically (Mistic Query Builder)

I'm new to JavaScript, focusing primarily on Java/PHP development. The JS applications I've built in the past have been pretty hackish, untestable, and unextensible.
I'm now trying to create an application that interfaces with data in a more appropriate manner. Basically I'm building a user interface for creating rules/actions that our support team and end users can access. The logic for the application contains a lot of Boolean and logical operators and just requires that some arbitrary set of conditions be met, and then will apply certain actions.
So, I've pretty much settled on a query builder type of application, and I love Mistic's work. Unfortunately, we don't have a Node.js server. So, I've set about finding ways to make this work with vanilla JS/jQuery. One iteration used Knockout.js. However, I found that API to be difficult to work with.
Now, I found this JSFiddle, which uses Mistic's work in a standalone version. I'd prefer to use this, but one thing I can't quite piece together is how to create multiple Query Builders dynamically. (Rules will appear in a table as shown in the second link, and I'll need an Add Row button).
$('#builder').queryBuilder({
sortable: true,
filters: [{
id: 'core_ID',
I've tried using the jQuery .each() function to create query builders bound to each element with a class of builder, but to no avail.
$.each('.builder').queryBuilder({
Can you guys show me how you'd go about dynamically creating new QueryBuilder objects as shown in the third link?
You use .builder as a selector, which means you select all elements that have a class="builder" attribute.
If that is so, then you should be able to just call $('.builder').queryBuilder(... and it should use all elements that have the class builder
EDIT: It does in fact do so. But the cakephp query builder doesn't allow it (for whatever reason). So you have to use each in the way that i describe.
if you want to use the each function, you would to it like that:
$( ".builder" ).each(function() {
$( this ).queryBuilder(...);
});
Explanation:
$(".builder") selects all elements that have a class="builder" attribute.
.each iterates over those elements. inside the function that is passed to each this contains the native DomElement (which is not a jquery element). Therefore $(this) gets the jQuery element for the DomElement and .queryBuilder is called on it.
you can call .queryBuilder on pretty much any jQuery element unless it is an array of elements (it will throw an error).
so basically any selector + each in the way I use it should work.
here is a working fiddle with your example using 4 querybuilders: http://jsfiddle.net/ap9gxo4L/42/

Need some clarification about jQuery objects that don't reside in the DOM

I was trying to use browser console to do some HTML code manipulation. In console, I input
s = $('<div><span>ddd</span></div>');
s.remove('span');
Be noted the jQuery object s is not in the DOM, it only lives in the console. It turns out the span isn't removed from s. On the other hand, if <div><span>ddd</span></div> was in HTML, the span will surely be removed.
This brings up a question that has been confusing me for a long time. If I understand right, using $(), I can turn many things into jQuery objects, even if they are not actually in the DOM. But what is the difference between this kind of jQuery objects and the those jQuery objects that are linked to some DOM elements? And in the above code, in order to actually remove the span and get an output as <div></div>, do I have to write it into DOM?
It's because you are not using $.fn.remove properly. Correct way to remove child span is to find it first:
s = $('<div><span>ddd</span></div>');
s.find('span').remove();
When you provide a selector to remove, jQuery filters supplied collection by this selector. However, in your case there is nothing that can be filtered out, since clearly div is not span. So s.remove('span'); removes nothing.

How jQuery data() breaks circular reference

I have read an why it's better and how it's implemented. But what i don't really understand is how does it break the circular reference?.
how does it break the reference circle?
$(div1).data('item', div2);
$(div2).data('item', div1);
like example, the divs above point to each other, how is it prevented? I have a hunch, but i just want to make sure if my hunch is right.
The circular reference problem happens in some browsers when you put a reference to a DOM object on a DOM object as a property on that DOM object. Then, you have two DOM objects pointing at each other. Removing a DOM object with a custom property on it doesn't clear that custom property. A garbage collector that isn't that smart doesn't realize that this DOM reference doesn't count so it gets stuck and there are several ways that this can lead to leaks.
.data() solves this problem because the .data() data is NOT on the DOM object. It's just a javascript data structure that can be associated with the DOM object via a unique string ID.
The one confusing part of this is that when you read with .data("key") and the key isn't found in the javascript .data() data structure, then and only then, jQuery will look for an attribute on the DOM object called "data-key". But whenever you write with .data("key", "myData"), it never writes to the DOM object, only to the javascript data structure.
Thus, since .data() never writes the data to the DOM object, there can't be any of these types of circular references that some browsers have trouble with.
There are some other useful things to know about the .data() data structure. When you use jQuery's .remove() to remove elements from the DOM or when you call $(elem).html("new html"), jQuery clears the .data() data on any removed items. This is one case where it's good not to mix jQuery with plain javascript. If you're using .data(), then you should always remove items from the DOM using jQuery functions so .data() is cleaned up appropriately. Otherwise, you can get memory leaks this way (both the .data() data can leak and any removed DOM objects that are referenced in the .data() can leak. But, if you only use jQuery methods for removing items from the DOM (including the replacing of innerHTML), then jQuery will clean things up appropriately and there will be no leaks.
So, for example, this will create a memory leak:
// suppose elem is a DOM element reference
// store some data in jQuery's data storage on behalf of a DOM element
$(elem).data("someKey", "someValue");
// remove DOM element with plain Javascript
elem.parentNode.removeChild(elem);
Because you removed the DOM element with plain Javascript, jQuery did not have a chance to clean up the data you previously stored. The DOM element itself will be garbage collected, but the .data() value you previously stored is now orphaned in jQuery's storage and is essentially a "leak" as it will likely never be cleared. On the other hand, if you do this:
$(elem).data("someKey", "someValue");
$(elem).remove();
Then, jQuery will see that you're removing the DOM element and will also clear the data you stored with .data().
A fairly simple way to see how it works is to create a couple line script with a non-minimized version of jQuery and then just step through a call to $(elem).data("key", "whatever") in the debugger and watch how it works.

Is using document.getElementsByTagName() a good idea or bad idea?

Ok so I am wondering which way is the preffered way to access a certain tag.
Is it better to use..
document.getElementById('myDiv').innerHTML
or this way..
document.getElementsByTagName('div')[0].innerHTML
// I use [0] because it is the first div in the body
My guess is that it doesn't matter at all which way i do it.
Absolutely the getElementById is better in that case. It's much faster.
Update
Here is a test about JavaScript selector functions. http://jsperf.com/queryselectorall-vs-getelementbyid/6
There are not many articles about performance of JavaScript selector functions. Instead there are many articles about jQuery selector performance like this or this. jQuery uses native JavaScript selector functions internally, so you can guess from these articles.
They do completely different things. If you want to get a particular element and you always need to get the same element, use an id. If you want to get a particular element based on what place it has in the DOM, then use the it's position in the getElementsByTagName NodeList.
If you want to get a particular element and you get it by index, then your script will be brittle - if you change your DOM structure later, you will need to change your code. If you want to get an element by it's position, then using an ID will require you to add redundant attributes to your markup.
Also, it is important to note that getElementById returns a DOM node, while getElementsByTagName returns a NodeList. To quote MDC on the properties of a NodeList:
NodeList is live, meaning that it updates itself automatically to stay in sync with the DOM tree without having to call document.getElementsByTagName again.
So if you need a particular element, getElementById will be significantly faster.
For readability purposes, it depends on what you're trying to do.
Is your intent to get the first div, which just happens to be named myDiv? if yes, then I think getElementsByTagName is better, as it would more express what you're trying to do.
Or is your intent to get myDiv, which just happens to be the first div? If that's the case, then use getElementById.
All other considerations aside, go with the one that expresses your intent.

What's the best way to get a list of the contents of a specific group of DOM elements in javascript?

The basic scenario: I've got a series of elements on an HTML page, generated dynamically. (Currently, they're all divs, but they don't need to be.)
What I want is a javascript function that will loop though all of those divs (or whatever) looking for the presence of a specific value.
What's the best, most cross-browser way to do this? Does getElementsByName() work on divs in all browsers? Can I give them all the same ID and get an array back out of getElementById somehow?
If I change those divs to spans or inputs, does that make things easier?
Thanks!
(edit: it would be best, for this project, if there was a solution without using any external js libraries. I assume jQuery has a function that does just this in one line, but for the moment I'd like to avoid opening that can of worms with the client.)
getElementsByTagName is defined in DOM Core, so any browser which implements that works. That's about every browser in current use.
Take a gander over here for the specifics: http://www.quirksmode.org/dom/w3c_core.html
One gotcha to be ware of, is that getElementsByTagName returns a NodeList - not an array. It works the same, but it is evaluated very late, so if you add/remove nodes to the DOM while traversing a NodeList, you will get weird results. In these cases, write two loops; First loop through the NodeList and store all entries in an array - Then loop through the array.
It doesn't matter what the elements are, but what does matter is where they are in the page. If they are all child elements of a single parent element, your problem is simple. Give the parent element an ID and you can use getElementById() to grab it and iterate its children.
getElementById() behavior is undefined when more than one instance of an ID is found in the document. Most will return the first Element they can find, but you certainly can't cound on getting an array.
getElementsByTagName() will work only if you can use some obscure tag that you are sure won't appear elsewhere in your page. You could augment this by specifying that the elements you are interested in will have an attribute present that you can check for (such as #class or #title). You can then loop through the result of getElementsByTagName() checking for this and only look at Elements where the attribute is present.
You can use this site to see what getElementBy most suites your needs.
There are some using libraries and some like troelskn wrote that apply for standard javascript in all supporting browsers.

Categories

Resources