I'm reading Bibeault's jQuery in Action and I'm having troublel understanding the value parameter of the attr() method. The book says that the parameter can be a function whose parameters are index and previousValue. What is the purpose of these parameters? I don't understand the text's explanation.
Specifically I want to know:
Are these parameters mandatory?
What is an example of how these parameters are used?
Can I use other parameters within the function?
1) No parameters are mandatory in javascript. You use whatever amount you want. These parameters are available for you in your function.
2) examples:
Let's say you have this html:
Now, run this snippet:
$('a').attr('title', function(index, previousValue){
return previousValue + ' - An external link';
});
This will add the string " - An external link" to the end of every title.
Now, look at this:
$('a').attr('title', function(index, previousValue){
return previousValue + ' - Link number ' + index;
});
This will result in the following html:
As you can see, you can see, these parameters are very handy.
3) Not sure what you mean by using other parameters. Please clarify.
It seems that you are not familiar with Javascript's scope lookup chain. You do not have to explicitly pass parameters to a function. If they're defined in a scope above it, the function will have access to it:
var num1 = 23;
var num2 = 54;
$('a').attr('title', function(){
return num1 + num2;
});
It's actually pretty simple. The attr() function has three possible modes; the one you refer to takes a callback to get the value.
For example:
$('.someClass').attr('rel', function(index, value)
{
// index refers to the elements index of the set; so of all elements with the
// css class 'someClass', the index will refer to that position in the list.
// If three elements match, the callback will be invoked 3 times, with 0, 1, 2
// as the index when each element, respectively, is invoked.
// value refers to the current value of the attribute.
// Return the value you want to set.
return 'SomeRelValue';
});
The parameters are not mandatory; if you simply omit them from the callback signature, you simply dont have access to that information. You cannot pass other parameters to this method. You might want to use this function when you will match a lot of elements, and want to insert some data based on their ordinal position of the selector element.
For example:
$('.someElements').attr('rel', function(index, value)
{
return value + index;
});
For each element matching the selector, you set the rel attribute to what it was plus the index of the selector. So element one, if it had a rel of 'sampleRel', is set to 'sampleRel1', element two with rel' sampleRel' becomes 'sampleRel2', etc etc
There's a good example in jQuery's documentation, which I'll shorten here:
Here's the relevant HTML:
<div>Zero-th </div>
<div>First </div>
<div>Second </div>
If you then run this javascript it'll apply unique id's to each div:
$("div").attr("id", function (arr) {
return "div-id" + arr;
});
The $ function returns all of the div's so the arr argument allows you to specify the attribute value based on the index.
The function passed to attr also received a value specifying the old attribute value, but as this is javascript the function doesn't have to name that argument and it's still available in the arguments.
attr is a way to access attributes on an element. the overload which allows a function will allow you to use the function return to set the value (the index param to the function would be the index into the selection, previousValue being the value it had until now).
I've never used this overload myself, but assume it would be nice if you're making attribute values based on some sort of function.
They are not mandatory, passing different number of parameters gives different functionality:
attr('name') - gets the value of name
attr('name','value') - sets the value of name
attr('name',function(i,v){return v+i;}); - sets the value of name to the previous value + the index in the collection.
example:
lets say we have five spans with the class hiccup and name 'yup'.
$('span.hiccup').attr('name',function(i,v){return v + i;});
will give each span a name 'yup1' - 'yup5'.
Additionally, you have access to this inside the function, which refers to the element itself. Given this, you could probably do some really interesting stuff.
As always, jQuery has awesome documentation of all of this:
http://api.jquery.com/attr
Related
i have a string objects of books which i have got from a JSON objects. This Book object has three Key value pairs, Title,Author and URL. I use a for loop to read each object and just put the title of the object as a button on the html page. But when the button is clicked i want the URL of the book to be alerted. As i read the objects i make Books objects and push it into an array for later use. but i am not able to Use .Click() method the URL is not right. Please see the code for better understanding. :-)
for (i = 0; i < 6; i++) //I know that there is only 65 Books..jsonString.books.lenght is not working.
{
var title = jsonString.books[i].title;
var classname = title.replace(/\s/g, "");
var author = jsonString.books[i].author;
var URL = jsonString.books[i].url;
var htmlString = '<div class="' + classname + '"><input type="button" value="' + title + '"></div>';
$(htmlString).appendTo(attachPoint).click(function () {
loadBook(URL);
});
OneBook = new Book(author, title, URL);
arr.push(OneBook);
}
attachpoint is a reference in the html file that i got from
var attachpoint=document.querySelector('.buttonAttachPoint');
So in the above code the URL that i get on clicking is always the last object in the jsonString. this is happening coz of the for loop. So is there a way i can get to class name of the Div that has onclick or the title of the button so that i can get the URL from the array of objects i created? Or is there an easier way. Also could any one point out why "jsonString.books.lenght" is not working? Thanks in advance.:-) all the help much appreciated. :-)
Creating a closure using an immediately invoked function expression should do the trick. Just replace this:
$(htmlString).appendTo(attachPoint).click(function () {
loadBook(URL);
});
with this:
(function(URL) {
$(htmlString).appendTo(attachPoint).click(function () {
loadBook(URL);
});
})(URL);
URL inside the scope of that anonymous function will have the value passed to it, which will be the correct value for that iteration of the for loop.
In ECMAScript, variables are scoped to their function, rather than any block.
The functions you are binding to click have a closure over URL in the context of the loop as a whole, not over URL in the context of the loop iteration.
This means that whenever any of the functions are invoked, URL will have the last value that the loop sets it to.
You need to freeze the value of URL for each loop. One way to do this is to have a function elsewhere that takes URL as an argument, and returns a function that closes over it, thus:
function getBookLoader(url) {
return function (){
loadBook(url);
};
}
You can then replace your ... .click line with the following:
$(htmlString).appendTo(attachPoint).click(getBookLoader(URL))
To answer the question in the title, the target property of an event contains the object to which the event was dispatched, and the currentTarget property contains the object whose listeners are currently being evaluated. currentTargetshould be the div in question.
Could someone please explain, why do we need each(function (i)
what does (i) do? seems like i could be any letters.
why (i) is necessary? I don't quite understand. Many Thanks
<body>
<div>Click here</div>
<div>to iterate through</div>
<div>these divs.</div>
<script>
$(document.body).click(function () {
$( "div" ).each(function (i) {
if ( this.style.color != "blue" ) {
this.style.color = "blue";
} else {
this.style.color = "";
}
});
});
</script>
The first parameter for the callback function is the index of the iteration in the loop. i.e. the loop counter. In your case you don't need it at all, as you are not using it:
$("div").each(function() {
if (this.style.color != "blue") {
this.style.color = "blue";
} else {
this.style.color = "";
}
});
The second parameter is the element for the current iteration, i.e. the same as this is referring to. You could use that parameter instead of this. Of course, to use the second parameter you have to specify the first parameter also, even if you don't use it:
$("div").each(function(i, e) {
if (e.style.color != "blue") {
e.style.color = "blue";
} else {
e.style.color = "";
}
});
That can be any name you want, it's the index of The item, in case that's useful in the function. It's explained in the jQuery documentation. http://api.jquery.com/each/
You can call i whatever you want in the callback function, the each method will call that callback for each object that matches your each selector (In your case all divs) and will pass it to your callback parameter (i) or whatever you call so you can manipulate each of those objects for each iteration.
Hope i made myself clear,
Cheers
Well, I don't know if this is what you are asking but according to documentation
.each( function(index, Element) )
That's the signature, so i in your case would be the argument for the index of current item. So if there 10 things in your div, every time the function is called it would pass the index i for i-th element in your div.
.each is used for iterating over the collection of elements it is applied to. The first parameter (i, in your example) provides the index value of the current element within the collection.
The full signature is:
.each( function(index, Element) )
while you are using the overload of:
.each( function(index) )
And it doesn't really matter how you name the parameter in your function specification (index, i, blah, param1, etc), the index value will be passed into that parameter.
In your example, this parameter value provides no additional benefit as it is not required by your use case, however, there are plenty of use cases where it is an essential parameter.
i,j,k are a standard notation for integers. It is naturally used for looping through enumerable lists (like arrays or nodelists) where each element index is an integer. For imbricated loops the first level will use i, the second j, etc.
This is just a convention and in practice you can use other names, for example "index" as shown in the jQuery documentation that makes your code more readable. The drawback is that it makes your script longer, but with today's widespread use of minification/compression this should not be a concern.
And of course if you don't reference the index within the loop you can just omit it.
If I do this:
$('.classname').html(Math.floor(Math.random()*10)+1);
All of "classname" is filled with the same number.
Is it possible to fill every instance of "classname" with a different random number?
The only possible way I can think of solving this is to go through each instance of "class name" and apply a random number one by one.
.html()
$(".classname").html(function(idx, oldValue) {
return (Math.floor(Math.random()*10)+1);
});
fiddle
the html method has an "overload" that accepts a function. The function should return the value to set the inner html to. In your case you can do:
$(".classname").html(function() {
return (Math.floor(Math.random()*10)+1);
});
the function is actually called with two arguments. The first is the index of the element in the selection and the second is the current value of the elements inner html
You can use jQuery's .each() function to iterate over each element matching the selector you provide -
$.each('.classname',function(index,elem){
var newRandomNumber = (Math.random()*10)+1;
$(elem).html(Math.floor(newRandomNumber));
});
For every iteration of the each() function, you'll have the index of the element you are on and the element itself in the elem parameters.
http://api.jquery.com/jQuery.each/
try this
$('.classname').each(function(index) {
$(this).html(Math.floor(Math.random()*10)+1);
});
Yes. The easiest way to do so would be using the jQuery each function:
$('.classname').each(function() {
$(this).html(Math.floor(Math.random()*10)+1);
});
function ExChgClsName(Obj,NameA,NameB){
var Obj=document.getElementById(Obj)?document.getElementById(Obj):Obj;
Obj.className=Obj.className==NameA?NameB:NameA;
}
<a href="javascript:showMenu(2);">
i am a newbie of the js. so can't understand the above two function very well. expect someone can explain the line's meaning to me one by one. many thanks.
For the first function
var Obj=document.getElementById(Obj)?document.getElementById(Obj):Obj;
The first line gets the object by its ID if Obj is a string that is the ID of a DOM element. Otherwise it leaves the value of Obj alone. This is using the "ternary conditional" operator, a? b: c. which as a value of b if a is truthy and c otherwise. Doing this allows the function to accept a string or a DOM element.
Obj.className=Obj.className==NameA?NameB:NameA;
The next line sets the CSS class of the DOM element from the last line to NameB if the CSS class of the DOM element is NameA and otherwise sets it to NameA. This would have the effect of swapping out the classes so long as another class is never assigned to the element. If another class is assigned to the element, then it will start the cycle again with NameA.
function showMenu(iNo){
ExChgClsName("Menu_"+iNo,"MenuBox","MenuBox2");
}
The second function just applies the first to swap the CSS class of the the DOM element with ID of "Menu_"+iNo between "MenuBox" and "MenuBox2".
Personally, I don't like the first line of the first function because it does two searches of the DOM when it only needs to do one. I would do this
var Obj = document.getElementById(Obj) || Obj;
That should be more efficient on all implementations and is surely more readable. It uses the || operator as a guard to assign Obj back to itself if only if document.getElementById returns null.
Exchange the cascading style sheet class name on an object from A to B
Find the element
if the object's css class name is nameA, set it to nameB, otherwise, set it to nameA
function ExChgClsName(Obj,NameA,NameB){
//ternary operator, sets Obj = the dom object with id = 1st agrument if it exists
//you can get away with this because an object is "truthy" in javascript
// truthy meaning that if you try to evaluate it as a boolean it is the same as true
// if nothing is found getElementById returns null wich is the same as false
var Obj=document.getElementById(Obj)?document.getElementById(Obj):Obj;
//ternary operator again. changes the class of the dom object to the 3rd argument
//if its class is already the 2nd argument
//otherwise it changes it to the second argument
Obj.className=Obj.className==NameA?NameB:NameA;
}
function showMenu(iNo){
//calls exChgCLsName with the specified arguments
ExChgClsName("Menu_"+iNo,"MenuBox","MenuBox2");
}
// Runs the showMenu function when clicked
<a href="javascript:showMenu(2);">
I am trying to get the values of several fields & add them together & in my testing I am having problems. I have this code:
var count;
function calculate() {
// Fix jQuery conflicts
jQuery.noConflict();
count = 0;
jQuery('.calculate').each(function() {
var currentElement = jQuery(this);
var value = currentElement.val();
var count = count + value;
alert(count);
});
}
I enter in the value of "9" in my first field & when the first alert triggers I get "undefined9"; all the other values are currently set to "0"; when it triggers again I always get "undefined0".
Why am I getting the "undefined" bit & why is it only returning the value of the current field & not adding them together?
You are dimensioning the count value inside the loop, essentially setting it to undefined first in each iteration.
You want to remove the var within the loop. This way, it doesn't have scope to the anonymous function and JavaScript will look at the parent function for its declaration.
It may also be a good idea to parseInt(count, 10) the number first, because JavaScript overloads the + operator to mean arithmetic addition and string concatenation, and you wouldn't want count to be "0something".
Finally, count += value is easier to read :)
You're accidentally re-declaring count:
var count = count + value;
should be:
count = count + value;
The count declared in the inner-most scope (that of calculate) will hide the other one (this is called "shadowing" of variables).
The reason you get "undefined9" is because the default value of the newly-declared count variable is undefined; when you add to it, it sees an undefined value on the left, and a number on the right, and decides that string concatenation is the best way to perform the addition, resulting in the string "undefined9".
It has to guess at your intended meaning since + is overloaded to mean both numerical addition and string concatenation; in this case, it guesses wrong.
You're defining count in two different scopes - the calculate function, and then in the function that each is using. You may want to have the second count be named something else, or at least don't redeclare it.