I've recently come across a code sample I had to use, and I was able to use it, but I didn't quite understand exactly what was going on.
Here's part of the code:
.sortElements(function(a, b){
return $.text([a]) > $.text([b]) ?
inverse ? -1 : 1
: inverse ? 1 : -1;
}
I know that this function is deciding which element should be sorted first out of a and b, and I know that inverse is deciding the sort order, but I don't know what $.text([a]) is doing. Is it parsing a as text kind of like parseInt(a) and Date.parse(a)?
Google could not help me. I've also looked into the jQuery site and all I've found is
$(selector).text(), $(selector).text(newText) function.
Here's the Fiddle I'm basing my code from http://jsfiddle.net/gFzCk/
jQuery.text does the heavy lifting for the implementation for the .text() method -- it seems to be an undocumented function with the core functionality for .text(), but missing some jQuery polish.
It's "imported" from Sizzle, where it appears as Sizzle.getText.
Inspecting the jQuery source will reveal that the $(selector).text() that you're familiar with, uses $.text internally:
jQuery.fn.extend({
text: function( value ) {
return jQuery.access( this, function( value ) {
return value === undefined ?
jQuery.text( this ) :
this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );
}, null, value, arguments.length );
},
It is an undocumented function (which means further jQuery revisions may drop it at will, without notifying you). You'll find its definition as such:
jQuery.text = Sizzle.getText;
Sizzle.getText, in turn, is documented as "Utility function for retrieving the text value of an array of DOM nodes". Seeing as Sizzle.getText is a documented feature, I would recommend using that rather than the jQuery shorthand, as I don't expect jQuery to drop Sizzle any time soon.
This function, then, is the piece of code that yields the text content of a DOM node. Your sorting method is sorting DOM nodes by the alphabetical order of their text content. I don't know why the author has decided to get the text of an array containing only one element ([a]), rather than passing the element immediately (a), which would work equally well.
After looking at your jsfiddle it appears it's a function for getting the text from an element, simular to .text()
console.log(a) logged <td>28/02/2013</td>
While
console.log($.text[a]) logged 28/02/2013
If the code above does something useful (= there is no indication it does according to the jQuery documentation), then it probably calls .text() on a and b.
I'm wondering why the author didn't use $(a).text() because that should do the same. Maybe the code also works no matter whether a is a jquery wrapped node or not :-/
First of all, the brackets. if a is an element, [a] is a element array, so the calls to $.text(...) are passing an array as parameter.
I couldn't find any documentation about jQuery.text but only for jQuery.fn.text. However, you can see that the implementation of jQuery.text handles arrays as parameters as well as scalar values.
In this case, $.text([a]) is probably just the same as $.text(a).
Related
There are quite a number of jQuery methods that accept functions instead of values as parameters. .append() is an example of that. Instead of writing:
something.append( '<div></div>' );
one might write:
something.append( () => '<div></div>' );
That's... nice. But I'm wrecking my mind trying to come up with a use case for this. Why would I want to do that? Does this enable something that would not otherwise be possible? Or does it at least drastically shorten or beautify certain bits of code?
Just to quickly add the purpose of this question: I'm writing a JS library that doesn't operate on HTML but still might as well have an API that's similar to jQuery's. So now I'm trying to figure out what to copy and what not to.
EDIT:
One use case is to index elements based on their position in the matched set. (Thanks to #Satpal and #JasonSmith!)
A second use case is to conditionally add content - as long as there's no condition that requires not to add content. (Thanks again to #JasonSmith)
Are there other practical use-cases? Does this get used often?
In .append(fn) method. With in the function, this refers to the current element in the set. which lets us to manipulate the content to be appended.
Here is an example.
$('p').append(function(){
return $(this).index();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p></p>
<p></p>
<p></p>
<p></p>
OR
$('p').append(function(){
return $(this).next('a');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p></p>1
<p></p>2
<p></p>3
<p></p>4
#Satpal provided an excellent example of one use case using the append function in jQuery. In more general terms, however, I look at it this way: if you are creating an API method capable of operating on a set of objects, then accepting a function as an argument for that API method allows the user to vary the behavior of the API according to the unique properties of each object in the set. For example, suppose we have a collection of elements like this:
<li>100</li>
<li>1000</li>
<li>150</li>
Suppose also that we have a hypothetical API method called myAPI.colorize(). If the colorize function accepts only a string, then all items in the set will be made the same color
mySet.colorize('red');
If, on the other hand the colorize method also accepts a function as an argument, then the developer can dynamically colorize without being required to break the set into constituent parts, like this:
mySet.colorize(function(currentElement) {
return currentElement.text == '1000' ? 'green' : 'red';
});
Or, if our hypothetical API binds the this reference the way jQuery does, then we could make our code even simpler:
mySet.colorize(function() {
return this.text == '1000' ? 'green' : 'red';
});
Of course this is a somewhat contrived example, but I believe it illustrates the design point in question without getting too stuck on a specific feature of jQuery.
Let's say you have a website of 100 pages and there is a div with an id of #unique-div that only appears in page-5.html, but not in the other 99 pages and to be extra simple with the example you have a JS file that is loaded on all pages, and inside it there is this:
var uniqueDiv = $('#unique-div');
uniqueDiv.addClass('random-class');
does that have any negative impact in any possible way (for instance, performance)? Would it better to do a length check first?
var uniqueDiv = $('#unique-div');
if ( uniqueDiv.length ) {
uniqueDiv.addClass('random-class');
}
If so, why?
Or what about if you are chaining objects like this:
var uniqueDiv = $('#unique-div');
someVar.add(moreVars).add(uniqueDiv).addClass('random-class');
If the object doesn't exist, what happens?
I tried looking this up, but I have always wondered this.
It is the responsibility of ANY jQuery method to have a "proper" behavior whether there are 0, 1 or more than 1 DOM objects in the current jQuery object that they are called on. So, as long as you aren't using some broken jQuery plug-in methods, you do not have to test the length before calling a method and this includes situations where you are using chaining.
So, in your case this would be perfectly fine, even if you had no idea whether #unique-div actually existed:
$('#unique-div').addClass('random-class');
If the div didn't exist, then the .addClass() method would just do nothing.
Note: that some methods that retrieve a value such as .val() are coded to only operate on the first DOM element in a jQuery object and you will have to check with an individual method like that what they are coded to return if there are no DOM objects in the jQuery object. For example, .val() will return undefined when there are no DOM objects in the jQuery object.
There might be some infinitesimal amount of performance saving, but it's really negligible. There are probably going to be plenty of times in your code you'll do a for-loop through an array, acknowledging the length might be zero.
JQuery objects always have some size to them, and all methods I know of (ie, addClass) are equipped for empty sets, so I don't see any issue with skipping the length check.
Hello this seems to be working on IE8 :
var clsName = link.parents("div.fixed_column").attr("class").split(" ");
if($.inArray("column_one", clsName)
While this one reports error (Object expected errror in jquery).
var clsName = link.parents("div.fixed_column").attr("class");
What is the right way to do this? I thought purpose of inArray was that jquery will handle cross browser issues.
Unfortunately, this is indirectly answering your question, but... You seem to be looking to detect if an element has a class, and since you're already using jQuery, just use the hasClass method - http://api.jquery.com/hasClass/
For your specific code, try:
if (link.parents("div.fixed_column").hasClass("column_one")) {
// It has the "column_one" class
}
The more immediate answer to your question is that link.parents("div.fixed_column").attr("class") returns a single string. When the jQuery selector (div.fixed_column) returns multiple elements, which is very possible when using classes, using jQuery methods that get information (like .attr, using one parameter...to "get" the value) return the first matched element's value only.
So say the selector matches 3 elements:
["<div id='div30' class='fixed_column div30_class'></div>",
"<div id='div2' class='fixed_column div2_class'></div>",
"<div id='div17' class='fixed_column div17_class'></div>"]
Then the value returned from .attr("class") will be: fixed_column div30_class because it's the first matched element.
I'm not sure, but I think you're expecting jQuery to return an array of all the matched elements' values, which it just doesn't. So that doesn't mean jQuery isn't handling cross-browser issues, it just means you need to look up what the method does/returns.
I could've sworn that jQuery 2.0 has options for doing what you want - directly from calling the getters (or something similar), but I can't find it anymore :( Maybe I'm remembering incorrectly. Anyways, you could easily use $.each and/or $.map to look at every matched element, but it depends on what you were really trying to do with it.
You can't read the attributes of multiple elements into an array with .attr("class"). But why don't you just target the desired class in the selector like this?
var cols = link.parents("div.fixed_column.column_one");
Then change your conditional to check for an empty set:
if(cols.length) { ...
Being fully self-taught without actually reading up on JavaScript (It's my job now, believe it or not) there are a few things I accept but don't understand.
The first one is the dollar sign.
As far as I use understand it, it's a shortcut to document.getElementById(),
but if I log $ and document.getElementById() to console - Only $ returns a value. This value however is always function(), shouldn't it be. The element? What gives?
The second issue I have is something that keeps coming up in my code and I go out of my way to change the code to eliminate it. It's the "... is not a function" error.
For example:
if ($.inArray($(div_id).val(), arr) >= 0);
Will give the error .val() is not a function. Why? And how do I use the value of div_id to see if it's in array?
Hiya. When you're using Jquery (which I assume you are), then $ will return the jquery object. This can contain an array of matched HTML elements depending on the selector you used. For example $("#foo") will return the jquery object containing the element with id foo. You can get the actual HTML DOM element out using $("#foo")[0] - using the array-style notation.
Can you give us some more info on what you're trying to achieve with the $.inArray example?
$ is a valid variable name.
So if you try to use $ without setting it, it will not work.
A lot of people/frameworks however use $ as a shortcut to document.getElementById, they would declare it at the top of the script as:
function $(id) { return document.getElementById(id); }
$ and document.getElementById is not one of the same thing. $ gives you a function in console only when you are using some library like jquery which mapes $ to a function.
.val id primarly used to get value of the form elements and that is a jquery function. I think you need to learn more around javascript and jQuery
Neither Javascript nor the DOM define $, which (as other answerers said) is often defined in general-purpose DOM libraries like jQuery, Prototype or Mootools. Based on the particular code you included, I suspect you've been coding against the jQuery API (because you use $.inArray, see http://api.jquery.com/jQuery.inArray/; though your claim that $ aliases document.getElementById confuses matters, as jQuery expects CSS selectors rather than element IDs).
When $ is expected but undefined, that usually means you'll need to include the library whose API you're using in the HTML document.
i'm using DD_Belated.png to save all IE6 users from seeing the madness of unsupported png.
However, this great script takes either selector or DOM Element as parameter to it's only function to do it's magic and return working PNG to IE6.
Me, being lazy programmer, did something like this:
$("img[src$=png], #search").each (
function() {
DD_belatedPNG.fix( *what-here* );
});
SO, basically I need some jQuery function to return DOM Element from $(this).
BTW, neither $(this).get(), $(this).get(0) nor $(this)[0] does work in IE6
Thank you.
Edit: Once again, the problem was between monitor and seat - in me. There are two methods - one for selector string and one for DOM Element. I used the first one for both - and I thought I'm not passing good argument with this, so I began to look into different - well, I did not gave the right argument - It expected string...
In your .each function, the "this" variable will be your DOM element. Thus:
DD_belatedPNG.fix(this);
should do it.
I'll add, sadly, that I've never gotten any IE6 PNG fixers to work, at least not really work.
did you try DD_belatedPNG.fix(this);