Sorry for bad wording in the question but it's hard to explain for me. I'm using several bxsliders on a page and some are placed in hidden divs. Unfortunately images are not shown in the slider after making the parent div visible unless the slider is reloaded (See here: bxSlider within show/hide divs). So let's say I initiate the sliders at the beginning with:
var slider_0=$("#slider_0 .bxslider").bxSlider({
//bxslider options here
});
var slider_4=$("#slider_4 .bxslider").bxSlider({
//bxslider options here
});
var slider_7=$("#slider_7 .bxslider").bxSlider({
//bxslider options here
});
The sliders are not consecutively numbered but there is a navigation and if I click the 7th element it leads to slider_7. So I could get the index of the clicked item with:
$(this).index();
When I call slider_7.reloadSlider(); it would work but I don't know which slider the user clicks and which number it has. So would it be possible to call that with a created string like this:
slider_name='slider_'+$(this).index();
slider_name.reloadSlider();
works not of course. Is there a way to do it?
I would create a dictionary with strings as keys and functions as values. Then, you could have O(1) lookup of the functions you're targeting.
In general, you can do it like so:
// set up your dictionary
var dictionary = {};
// add your functions
dictionary['methodName'] = function() {};
// call the functions
dictionary['methodName']();
So, for your example, you could do:
dictionary['slider_7'] = slider_7.reloadSlider;
dictionary['slider_'+$(this).index()]();
You could trigger it with
window["slider_" + $(this).index()].reloadSlider()
Although, I'm not sure whether your approach is the best. I think I'd go with arrays or with object (as a key-value pairs)
Try this:
slider_name='slider_'+$(this).index();
$("#" + slider_name + " .bx_slider").reloadSlider();
Found a working solution:
eval("slider_" + $(this).index()).reloadSlider();
Its not entirely clear here what you want/are trying to do. What it seems like you want to do is get a programmatic handle on a specific slider when a user clicks a specific part of your page. You do not accomplish this by eval()ing a string...that's what event handlers are for. So create a click event handler and in that event handler
$('#idOfWhatTheUserClicksOn').click(function(event) {
var slider = document.getElementById('#idOfRelatedSlider');
$(slider).bxSlider();
//if you need the current value of the slider you can get that too
var value = slider.value;
});
You could achieve the same with fewer LOC by using a class instead of id's with different handlers, but the concept is the same.
var slider_cache = [
$("#slider_0 .bxslider").bxSlider(),
$("#slider_1 .bxslider").bxSlider(),
$("#slider_2 .bxslider").bxSlider()
];
...
slider_cache[$(this).index()].reloadSlider();
I see a lot of jQuery examples that do something like
var $element = $('#element');
$element.foo...
rather than just typing
$('#element').foo...
and I do realize there is a small bit of typing saved if you are working with
$element
a lot, but what about those times that
$element
is only called once or twice? Why do some developers declare it as a jQuery object variable in those instances? Is it also more efficient for the browser to process?
Usually this is done to avoid either re-wrapping an element or re-querying the page for the selector.
Such as in a click event
$('.className').click(function(){
var $this = $(this);
callSomeHelper($this);
$this.hide();
if( $this.data("placement") == "somePlacement" ){
//some logic
}
});
The real saver is when it is referencing a set of elements.
var $allSides = $('.side');
And now back in the click event, you can reference this without having to re-query
$('.top').click(function(){
var door = $allSides.find(':visible');
});
There are obviously more in depth examples, but these two are the main cases that the variable is stored.
It prevents from overwriting variable from another script
I have several <select> boxes all using the same prefix and I would like to set up a recursive function to essentially do the work for me.
$('[id^="by_"]').change(function(e)
{
var elem = e;
console.log(e.value);
});
Based on this code is my intention pretty clear? Am I on the right track?
console prints out: undefined
I think you're on the right track - the selector you're using matches a prefix of "by_", and you're binding the change event to all of them. Make sure you put this in $(document).ready or similar. Are you having any problems with this code? Instead of using the e parameter, I would just use this inside of the function to refer to the element and $(this) to get the jQuery object of it. So to get the value, you'd use:
this.value
// or
$(this).val()
(ignore the e and elem stuff, although it wouldn't be a bad idea to store $(this) in something like elem so you can have a reference to it instead of re-creating the jQuery object every time you need it)
When using callbacks to events with jQuery, the (first) parameter of the callback is an event object that explains many things about the event that occurred ( http://api.jquery.com/category/events/event-object/ ) and does not hold the element - that's what this is for!
e in your code is the event object which has no value property, you should use this instead:
$('[id^="by_"]').change(function(e) {
var elem = this;
console.log(this.value);
});
Or if you want to use event object, you can use target property:
e.target.value
Since you're already using jQuery, why not something like this:
$('[id^="by_"]').change(function(e)
{
var $elem = $( this );
console.log( $elem.val() );
});
Isn't it more something like that:
$('[id^="by_"]').change(function()
{
console.log($('option:selected',this).val());
});
jsfiddle
Hi this question is more a consulting of best practice, Sometimes when I'm building a complete ajax application I usually add elements dynamically for example. When you'r adding a list of items, I do something like:
var template = new Template("<li id='list#{id}'>#{value}</li>");
var arrayTemplate = [];
arrayOfItem.each(function(item, index){
arrayTemplate.push(template.evaluate( id : index, value : item))
});
after this two options add the list via "update" or "insert"
----- $("elementToUpdate").update("<ul>" + arrayTemplate.join("") + "</ul">);
the question is
how can I add the event handler without repeat the process of read the array, this is because if you try add a Event before the update or insert you will get an Error because the element isn't still on the DOM.
so what I'm doing by now is after insert or update:
arrayOfItem.each(function(item, index){
$("list" + index).observe("click", function(){
alert("I see the world");
})
});
so the question is exist a better way to doing this??????
I won't do $("list" + index).
There are two ways I would consider:
1) Let the click-event bubble up and catch in in $("elementToUpdate"):
$("elementToUpdate").observe("click", function(evt){
alert("I see the world");
});
You can find which li is clicked in the evt-object.
2) Don't do repeatetly $("list" + index), but just
$("elementToUpdate").find("li").each(...);
(Presuming you're using jQuery. Prototype has something similar).
Hi I post this question in Prototype Mail list and this is the answer
Hi,
If you really want to watch each individual li directly, then what
you have seems perfectly straightforward. But in that situation,
barring a really good reason to do it that way, I wouldn't use a
handler on each li; I'd listen for clicks on the elementToUpdate (or
the ul within it) instead with just a single handler:
$("elementToUpdate").observe("click", function(event) {
var li;
// Find out which `li` was clicked:
li = event.findElement("li");
if (li) {
// Do something with the `li`
}
});
Prototype 1.7 has a new feature to simplify that a bit:
$("elementToUpdate").on("click", "li", function(event, li) {
// Do something with the `li`; note it's given as the second
// argument to the function
});
...where behind the scenes, Prototype is basically doing what I did
above. You'll want the first version if you're still using 1.6 (and
since 1.7 is still at RC1, I expect you probably are).
HTH,
T.J. Crowder
Independent Software Consultant
tj / crowder software / com
www.crowdersoftware.com
the link is :http://groups.google.com/group/prototype-scriptaculous/browse_thread/thread/fec98641d72f6fea#
I'm writing a GreaseMonkey script where I'm iterating through a bunch of elements. For each element, I need a string ID that I can use to reference that element later. The element itself doesn't have an id attribute, and I can't modify the original document to give it one (although I can make DOM changes in my script). I can't store the references in my script because when I need them, the GreaseMonkey script itself will have gone out of scope. Is there some way to get at an "internal" ID that the browser uses, for example? A Firefox-only solution is fine; a cross-browser solution that could be applied in other scenarios would be awesome.
Edit:
If the GreaseMonkey script is out of scope, how are you referencing the elements later? They GreaseMonkey script is adding events to DOM objects. I can't store the references in an array or some other similar mechanism because when the event fires, the array will be gone because the GreaseMonkey script will have gone out of scope. So the event needs some way to know about the element reference that the script had when the event was attached. And the element in question is not the one to which it is attached.
Can't you just use a custom property on the element? Yes, but the problem is on the lookup. I'd have to resort to iterating through all the elements looking for the one that has that custom property set to the desired id. That would work, sure, but in large documents it could be very time consuming. I'm looking for something where the browser can do the lookup grunt work.
Wait, can you or can you not modify the document? I can't modify the source document, but I can make DOM changes in the script. I'll clarify in the question.
Can you not use closures? Closuses did turn out to work, although I initially thought they wouldn't. See my later post.
It sounds like the answer to the question: "Is there some internal browser ID I could use?" is "No."
The answer is no, there isn't an internal id you can access. Opera and IE (maybe Safari?) support .sourceIndex (which changes if DOM does) but Firefox has nothing of this sort.
You can simulate source-index by generating Xpath to a given node or finding the index of the node from document.getElementsByTagName('*') which will always return elements in source order.
All of this requires a completely static file of course. Changes to DOM will break the lookup.
What I don't understand is how you can loose references to nodes but not to (theoretical) internal id's? Either closures and assignments work or they don't. Or am I missing something?
Closure is the way to go. This way you'll have exact reference to the element that even will survive some shuffling of DOM.
Example for those who don't know closures:
var saved_element = findThatDOMNode();
document.body.onclick = function()
{
alert(saved_element); // it's still there!
}
If you had to store it in a cookie, then I recommend computing XPath for it (e.g. walk up the DOM counting previous siblings until you find element with an ID and you'll end up with something like [#id=foo]/div[4]/p[2]/a).
XPointer is W3C's solution to that problem.
A bit confused by the wording of your question - you say that you "need a string ID that [you] can use to reference that element later, " but that you "can't store the references in [your] script because when [you] need them, the GreaseMonkey script itself will have gone out of scope."
If the script will have gone out of scope, then how are you referencing them later?!
I am going to ignore the fact that I am confused by what you are getting at and tell you that I write Greasemonkey scripts quite often and can modify the DOM elements I access to give them an ID property. This is code you can use to get a pseudo-unique value for temporary use:
var PseudoGuid = new (function() {
this.empty = "00000000-0000-0000-0000-000000000000";
this.GetNew = function() {
var fourChars = function() {
return (((1 + Math.random()) * 0x10000)|0).toString(16).substring(1).toUpperCase();
}
return (fourChars() + fourChars() + "-" + fourChars() + "-" + fourChars() + "-" + fourChars() + "-" + fourChars() + fourChars() + fourChars());
};
})();
// usage example:
var tempId = PseudoGuid.GetNew();
someDomElement.id = tempId;
That works for me, I just tested it in a Greasemonkey script myself.
UPDATE: Closures are the way to go - personally, as a hard-core JavaScript developer, I don't know how you didn't think of those immediately. :)
myDomElement; // some DOM element we want later reference to
someOtherDomElement.addEventListener("click", function(e) {
// because of the closure, here we have a reference to myDomElement
doSomething(myDomElement);
}, false);
Now, myDomElement is one of the elements you apparently, from your description, already have around (since you were thinking of adding an ID to it, or whatever).
Maybe if you post an example of what you are trying to do, it would be easier to help you, assuming this doesn't.
UPDATE: Closures are indeed the answer. So after fiddling with it some more, I figured out why closures were initially problematic and how to fix it. The tricky thing with a closure is you have to be careful when iterating through the elements not to end up with all of your closures referencing the same element. For example, this doesn't work:
for (var i = 0; i < elements.length; i++) {
var element = elements[i];
var button = document.createElement("button");
button.addEventListener("click", function(ev) {
// do something with element here
}, false)
}
But this does:
var buildListener = function(element) {
return function(ev) {
// do something with event here
};
};
for (var i = 0; i < elements.length; i++) {
var element = elements[i];
var button = document.createElement("button");
button.addEventListener("click", buildListener(element), false)
}
Anyway, I decided not to select one answer because the question had two answers: 1) No, there are no internal IDs you can use; 2) you should use closures for this. So I simply upvoted the first people to say whether there were internal IDs or who recommended generating IDs, plus anyone who mentioned closures. Thanks for the help!
If you can write to the DOM (I'm sure you can). I would solve this like this:
Have a function return or generate an ID:
//(function () {
var idCounter = new Date().getTime();
function getId( node ) {
return (node.id) ? node.id : (node.id = 'tempIdPrefix_' + idCounter++ );
}
//})();
Use this to get ID's as needed:
var n = document.getElementById('someid');
getId(n); // returns "someid"
var n = document.getElementsByTagName('div')[1];
getId(n); // returns "tempIdPrefix_1224697942198"
This way you don't need to worry about what the HTML looks like when the server hands it to you.
If you're not modifying the DOM you can get them all by indexed order:
(Prototype example)
myNodes = document.body.descendants()
alert(document.body.descendants()[1].innerHTML)
You could loop through all of the nodes and give them a unique className that you could later select easily.
You can set the id attribute to a computed value. There is a function in the prototype library that can do this for you.
http://www.prototypejs.org/api/element/identify
My favorite javascript library is jQuery. Unfortunately jQuery does not have a function like identify. However, you can still set the id attribute to a value that you generate on your own.
http://docs.jquery.com/Attributes/attr#keyfn
Here is a partial snippet from jQuery docs that sets id for divs based on the position in the page:
$(document).ready(function(){
$("div").attr("id", function (arr) {
return "div-id" + arr;
});
});
You can generate a stable, unique identifier for any given node in a DOM with the following function:
function getUniqueKeyForNode (targetNode) {
const pieces = ['doc'];
let node = targetNode;
while (node && node.parentNode) {
pieces.push(Array.prototype.indexOf.call(node.parentNode.childNodes, node));
node = node.parentNode
}
return pieces.reverse().join('/');
}
This will create identifiers such as doc/0, doc/0/0, doc/0/1, doc/0/1/0, doc/0/1/1 for a structure like this one:
<div>
<div />
<div>
<div />
<div />
</div>
</div>
There are also a few optimisations and changes you can make, for example:
In the while loop, break when that node has an attribute you know to be unique, for example #id
Not reverse() the pieces, currently it is just there to look more like the DOM structure the ID's are generated from
Not include the first piece doc if you don't need an identifier for the document node
Save the identifier on the node in some way, and reuse that value for child nodes to avoid having to traverse all the way up the tree again.
If you're writing these identifiers back to XML, use another concatenation character if the attribute you're writing is restricted.
Use mouse and/or positional properties of the element to generate a unique ID.
In javascript, you could attach a custom ID field to the node
if(node.id) {
node.myId = node.id;
} else {
node.myId = createId();
}
// store myId
It's a bit of hack, but it'll give each and every node an id you can use. Of course, document.getElementById() won't pay attention to it.
You can also use pguid (page-unique identifier) for unique identifier generation:
pguid = b9j.pguid.next() // A unique id (suitable for a DOM element)
// is generated
// Something like "b9j-pguid-20a9ff-0"
...
pguid = b9j.pguid.next() // Another unique one... "b9j-pguid-20a9ff-1"
// Build a custom generator
var sequence = new b9j.pguid.Sequence({ namespace: "frobozz" })
pguid = sequence.next() "frobozz-c861e1-0"
http://appengine.bravo9.com/b9j/documentation/pguid.html
I 'think' I've just solved a problem similar to this. However, I'm using jQuery in a browser DOM environment.
var objA = $("selector to some dom element");
var objB = $("selector to some other dom element");
if( objA[0] === objB[0]) {
//GREAT! the two objects point to exactly the same dom node
}
OK, there is no ID associated to DOM element automatically.
DOM has a hierarchycal structure of elements which is the main information.
From this perspective, you can associate data to DOM elements with jQuery or jQLite. It can solve some issues when you have to bind custom data to elements.