On events in loop in dynamic elements - javascript

I need to set events to elements makes "on the fly", like var X = $('HTML CODE HERE'), but when I set the events to the last element, all other elements get this last event.
Example here: http://jsfiddle.net/QmxX4/6/
$(document).ready(function() {
var ulItem = $('.lst');
for (var x=0; x<5; x++) {
var newItemElement = $('<li style="border:solid 1px blue;width:200px;height:40px;"></li>');
ulItem.append(newItemElement);
var generator = Math.random();
newItemElement.on('click', function() {
console.log(generator);
});
}
});
All elements are diferents, and I attach the event in the element directly, im try to append before and after add event to element, but not work, all element get the last event.
If you make click in the <li></li> get code generated in the last event, but "in theory" all elements have diferent events attached..
But if I make other loop appending elements after append al items to <ul></ul>, like this:
$.each($(ulItem).children('li'), function(i, item) {
console.log($(this));
var generator = Math.random();
$(this).on('click', function() {
console.log(generator);
});
});
Works... what is the problem?

In your first loop, the generator variable belongs to the ready callback function, and the inner log functions all share it.
In your second loop, the generator variable belongs to the each callback function which is called once for each item and therefore the log functions all see a different variable.

Related

Attaching Click Event to DIV Using jQuery Library

I am aware I can use the click function to attach an event to the DIV element but for some reason it is not working for me. Here is how I am creating the DIV element.
function createColorSwatchDiv(color) {
var colorSwatchDiv = $("<div>");
var image = $("<img>");
image.attr("src",color.imageURL);
var label = $("<label>");
label.text(color.title);
colorSwatchDiv.append(image);
return colorSwatchDiv;
}
Then I try to attach the click event like the following:
// run a loop and build the grid layout
for(index = 0; index < colors.length; index++) {
var colorSwatchDiv = createColorSwatchDiv(colors[index]);
// attach the event
colorSwatchDiv.click(function(){
alert('hello world');
});
colorsSection.append(colorSwatchDiv);
}
// add to the dom
$("#color .imageChartOption").after(colorsSection);
But it does not work and no click event is been attached.
following is the code
var $newdiv1 = $("<div id='object1' onClick=Test()>Hello</div>");
$("body").append($newdiv1);
function Test()
{
alert("Clicked");
}
OR
$newdiv1.on('click',function(){alert("hello");});
since you have created the div in a jQuery wrapper you don't need to wrap it again here $(colorSwatchDiv).click(.... Also, are you sure that the colorSwatchDiv variable is referencing the dom element and not the in memory element? Can you apply a class or anything to the elm in the dom?

select one div and unselected another one

Working on the div's. I am doing changes that if one div is selected, it should deselect the another div.
The div's defined are in ul li
Like in every li, there is a div with same classname called as inonset. Now the div which is already selected is having a class of inonset isactive.
I am adding a onclick function on every <div class="inonset" onclick="selectme(divid)"> to select it and unselect other, but how the other will be unelected, I am lost
Here is the fiddle
Not have not added the javascript code yet, but from the code, it will clear what I am trying to do.
You will see initially one selected and others are there, i just trying to selected any other one and deselect the previous one, Hope my questions makes sense
Worst thing: I cannot use Jquery, Only Dojo or Plain Javascript
Update #1
<div class="optionsBox" align="left" id="Invoicing" onclick="chooseDiv(this);">
function chooseDiv(oObj){
var d = document.getElementsByClassName("ul li div");
alert(d.className);
It is giving me undefined and not looping over the classes
the div is having classes like
iv class="headerSelected isactive">
where isactive needs to be removed from the previous selected div and add to the newly selected Div
First u need to change on click event for this:
onclick="selectme(this)"
And then in function:
function selectme(oObj){
var d = document.getElementById("ul li div");
d.removeAttribute("class");
oObj.className = oObj.className + " otherclass";
}
It should work fine
I am not sure whether the answer is still required or not. However, posting my approach of doing it.
function removeClass(className) {
// convert the result to an Array object
var els = Array.prototype.slice.call(
document.getElementsByClassName(className)
);
for (var i = 0, l = els.length; i < l; i++) {
var el = els[i];
el.className = el.className.replace(
new RegExp('(^|\\s+)' + className + '(\\s+|$)', 'g'),
'$1'
);
}
}
var elements = document.getElementsByClassName("inoneset");
for (var i = 0; i < elements.length; i++) {
(function(i) {
elements[i].onclick = function() {
removeClass("isactive");
//this.setAttribute("class", this.getAttribute("class") + " isactive");
var headerElem = this.getElementsByClassName("headerSelected")[0];
headerElem.setAttribute("class", headerElem.getAttribute("class") + " isactive");
var addressElem = this.getElementsByClassName("selDelAddress")[0];
addressElem.setAttribute("class", addressElem.getAttribute("class") + " isactive");
var footerElem = this.getElementsByClassName("footerSelected")[0];
footerElem.setAttribute("class", footerElem.getAttribute("class") + " isactive");
};
})(i);
}
Fiddle - http://jsfiddle.net/38nv5rft/18/
Reasoning
As you can see, there is a remove class function, that removes the class from the elements in the document. One can update it as per the requirement.
Then the main logic, which gets all the elements, iterate on them and bind the click function.
In click function, we are removing the inActive class from every element and then for current block, adding inActive class. Please note, as per the fiddle, I did not find the class on inoneset elements being updated, hence, commented out the code.
Important Point
Click event bubbles, hence, click on elements with showDelete and showDialog click functions will bubble the event to click event of inoneset i.e. click handler of inoneset will also be triggered. In order to stop the propagation of event to it, use event.stopPropogation() in showDelete and showDialog functions.

How to use arrays in javascript to match up divs when event fires?

I have a set of two divs - First set: when people mouse over these divs, it will fire an event, Second set: when the event is fired, these divs will be displayed.
When you mouse over a div in the first set, it should display its corresponding div in the second set. I thought an easy way to match the mouseover divs with the correct div to display would be using arrays. I've been able attach the event listeners properly, but I can't figure out how to set it up so that when you mouseover one object of an array, it displays the array object with the same index number. I think if I could figure out how to recoginze the index number of the object I am mousing over, I could get it to work. I've tried a lot of things, but haven't been able to create anything that works. Here's the code:
<script>
$(document).ready(function(){
//create array of divs to mouse over
var ar = new Array();
ar[0] = $("#home");
ar[1] = $("#doc");
var length = ar.length;
//create array of divs to display when event is fired
var des = new Array();
des[0] = $("#homeDes");
des[1] = $("#docDes");
// start for
for ( var i = 0; i< length; ++i )
{
ar[i].bind("mouseover",function(){$(des[i]).css("display","block");});
ar[i].bind("mouseout",function(){$(des[i]).css("display","none");});
}
//end for
});
//end
</script>
I would tend toward making a more flexible approach to this so that you don't need to change your javascript when you change your HTML. Consider classing your elements that need to have the bindings and providing data attribute to specify the target. Your HTML for divs to be bound might look like this:
<div id="home" class="mouseoverToggleTrigger" data-target="#homeDes">...</div>
And the jQuery might look like this:
$(document).ready(function(){
$('.mouseoverToggleTrigger').hover(function() {
var $target = $($(this).data('target'));
$target.toggle();
}
});
Note this is assuming you are using HTML5 for which jQuery, by default, converts data-* into values retrievable via data().
For pages that are not HTML5, this more generalized solution will work
$(document).ready(function(){
$('.mouseoverToggleTrigger').hover(function() {
var $target = $($(this).prop('data-target'));
$target.toggle();
}
});
One additional bit of flexibility this gives, is that you now don't have to limit yourself to a one-to-one trigger to target mapping. You could specify a class name or other jQuery selector for data-target values to get highly customized behavior, such as one trigger toggling all elements of a certain class that are children of another class.
$(document).ready(function(){
//create array of divs to mouse over
var ar = new Array();
ar[0] = $("#home");
ar[1] = $("#doc");
var length = ar.length;
//create array of divs to display when event is fired
var des = new Array();
des[0] = $("#homeDes");
des[1] = $("#docDes");
// start for
for ( var i = 0; i< length; ++i )
{
// WRAP THE BODY OF THE FOR LOOP IN A FUNCTION
function(index) {
ar[index].bind("mouseover",function() {
$(des[index]).css("display","block");}
);
ar[index].bind("mouseout",function() {
$(des[index]).css("display","none");
});
}(i);
}
//end for
});
When the events are fired the value of i is the length of the array, you have to pass the value of i to another function so that in each function scope the value of index will be the value of i when it was called.
A simpler approach code wise is to give the common elements common classes and then use jQuery index() and eq() to match pairings
HTML
<a id="home" class="hoverMe">
<a id="doc" class="hoverMe">
<div id="homeDes" class="content">
<div id="docDes" class="content">
JS
var $content=$('.content')
var $links=$('.hoverMe').hover(function(){
$content.eq( $links.index(this) ).show()
},function(){
$content.eq( $links.index(this) ).hide()
})
index() API Docs
eq() API Docs

How to append an element, all its children, and all classes of the parent and children with jQuery

I have a function that is successful in removing an element and appending it elsewhere on the page as successful. The problem is that as soon as the document is ready jQuery adds classes and attributes to the children that upon moving are lost. I need these classes and attributes to remain after removing and appending. I have thought about calling the original function that adds the classes, but the problem is they are key based and rely on their position prior to the move, calling it after changes the key and thus will add brand new and different classes.
The classes adding jQuery is pretty standard:
$(function(){
$("div").each(function(key){
if ($(this).hasClass("container")){
$(this).find("ul").addClass("parent" + key);
$(this).find(".container-item").attr("parentClass", ".parent" + key);
};
});
});
The remove/append function:
function copy_item(draggable, target){
var account = clone_items(draggable);
//$('#'+name.uid).remove();
$('#'+name.uid).hide();
target.append(make_div(name, true, true));
//$(draggable).children().attr("class", ($(draggable).children().attr("class")));
}
function make_div(name, drag, drop){
var newdiv = document.createElement('div');
newdiv.setAttribute('id', name.uid);
newdiv.appendChild(make_h3(name.username));
ul = document.createElement('ul');
ul.setAttribute("class", "domain_list");
newdiv.appendChild(ul);
for (j = 0; j < name.domains.length; ++j) {
ul.appendChild(make_li(name.domains[j], drag));
}
return newdiv;
}
The end result in the HTMl is basically:
<div class="container">
<ul class="parent0">
<li parentClass="parent0">
<li parentClass="parent0">
When recreating this structure, I need to have the class "parent0" and the parentClass attribute intact. Above you can see I've tried hiding the element, ensuring that it still stays a valid element with the correct classes/attributes, but in the end that still didn't work out. Ideally, I could remove the element entirely and recreate it with the correct classes.
If I am correct in my understanding of what you are trying to do, you do not need to .remove() and recreate the element in order to move it. You can just do this:
function copy_item(draggable, target) {
// not sure what this variable is for
// as you don't seem to be using it?
var account = clone_items(draggable);
// ...however, appending an existing
// element to another will 'move' it
// and preserve all of it's properties
target.append($('#' + name.uid));
}

Why my element always return the same value in js?

Here is the code:
for(var i = 0; i<aLotOfItems.length; i++){
var tmpItem = aLotOfItems[i];
//this will generate a <a> for me to handle the event
tmpItem.toHTMLElement().prependTo($("#main"));
//bind the click event
$("#edit_"+tmpItem.m_sId).bind('click', function(){
alert(tmpItem.m_sId);
});
}
First, I have a aLotOfItems array, then I take it one by one, to pass it in a tmpItem Object. and this object, have some htmlContent, I take it out, than, prepend to main, the toHTMLElement also will generate a tag which use the edit_+m_sId to generate the id, then, I bind it to a click event. But finally, my result is all the click event is output the same result.... wt did I do wrong? Thank you.
It's because of clousres/variable scoping, your tmpItem.m_sId var will get only its last value. But if you do:
$("#edit_"+tmpItem.m_sId).bind('click', function(){
alert($(this).attr("id"));
});
you will surely get different results.
EDIT Just in case you need to acces to your tmpItem inside your click event, you could use .data as this:
for(var i = 0; i<aLotOfItems.length; i++){
var tmpItem = aLotOfItems[i];
//this will generate a <a> for me to handle the event
tmpItem.toHTMLElement().prependTo($("#main"));
//bind the click event
$("#edit_"+tmpItem.m_sId).data("tmpItem", tmpItem).bind('click', function(){
var tmpItem = $(this).data("tmpItem");
alert(tmpItem.m_sId);
});
}
Hope this helps. Cheers.

Categories

Resources