I been trying to figure this out, but I haven't yet.
I am building column in html of anchor tags and I would like to know the id of the one that has the mouse over it.
It should be simple, but seems like I hit a wall and I can't see how to solve this.
The problem I have is that the id that is display on the console is all the time the last id of the array. And instead of that I want to the id of the specific anchor.
Any suggestions are really welcome.
Here is my code:
//Anchor builder
var numberOf = flatParamDateArray.length;
for (i = 0; i < numberOf; i++) {
var param2Slider = document.createElement("a");
param2Slider.id = 'sliderAnchor' + i;
sliderAnchorId = param2Slider.id;
param2Slider.name = 'param2Slider';
param2Slider.className = 'nav2Slider a';
document.getElementById('nav2Slider').appendChild(param2Slider);
$('.nav2Slider a').onmouseover = function () {
console.log('flatParamDateArray index: ' + param2Slider.id);
}
}
1. Move this out, and after the for-loop:
$('.nav2Slider a').onmouseover = function () {
console.log('flatParamDateArray index: '+param2Slider.id);
}
2. Change onmouseover() to mouseover():
$('.nav2Slider a').mouseover(function() {
console.log('flatParamDateArray index: '+param2Slider.id);
});
3. To get the ID, this is the code you need:
console.log('flatParamDateArray index: '+ $(this).prop('id'));
Bonus:
Since you are dynamically adding links, you should use the .on() function, to reduce the number of event handlers to one (as opposed to one per element):
$('.nav2Slider').on('mouseover', 'a', function() {
console.log('flatParamDateArray index: '+ $(this).prop('id'));
});
Your variable param2Slider is global and the for loop changes the value on every loop. This means that after the loop is finished param2Slider just contains the last value.
Try this:
$('.nav2Slider a').on('onmouseover', function () {
console.log('flatParamDateArray index: ' + $(this).attr('id'));
});
Edit: onmouseover... & of course you should move this snippet out of the loop
Related
I'm having some trouble with jQuery in Meteor - I'm just trying to learn so I hope someone could help.
So when #addButton is clicked it will append the div to the .formField and each div created on click will have an unique class, eg formField[1], formField[2] etc
The trouble is when the button is clicked instead of just changing the name of the div only, the div is also added 50 times. I know how dumb it sounds as its a loop, but how would I loop only the div's class on click so each have a different name?
My code is below:
Template.form.events({
'click #addButton': function(event) {
var i;
for (i = 0; i < 50; i++) {
$(".formField").append('<div class="formField['+i+']">.....</div>');
}
return false;
If I understand what you are doing here you don't need a loop. You just need a variable to increment every time the button is clicked. Take your append out of the loop and instead on click increment your variable by one then call an append. No loop necessary.
var i = 0;
Template.form.events({
'click #addButton': function(event) {
i += 1;
$(".formField").append('<div class="formField['+i+']">.....</div>');
}
});
return false;
Do it like this, (i.e. by creating a closure), click run to verify
var uuid = 0;
$('#addButton').on('click', function (event) {
uuid = uuid + 1;
$(".formField").append('<div class="formField[' + uuid + ']">Form' + uuid + '</div>');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="formField"></div>
<input type="button" value="Add New" id="addButton"></input>
I've created a script that attaches an event listener to a collection of pictures by default. When the elements are clicked, the listener swaps out for another event that changes the image source and pushes the id of the element to an array, and that reverses if you click on the swapped image (the source changes back and the last element in the array is removed). There is a button to "clear" all of the images by setting the default source and resetting the event listener, but it doesn't fire reliably and sometimes fires with a delay, causing only the last element in a series to be collected.
TL;DR: An event fires very unreliably for no discernible reason, and I'd love to know why this is happening and how I should fix it. The JSFiddle and published version are available below.
I've uploaded the current version here, and you can trip the error by selecting multiple tables, pressing "Cancel", and selecting those buttons again. Normally the error starts on the second or third pass.
I've also got a fiddle.
The layout will be a bit wacky on desktops and laptops since it was designed for phone screens, but you'll be able to see the issue and inspect the code so that shouldn't be a problem.
Code blocks:
Unset all the selected tables:
function tableClear() {
//alert(document.getElementsByClassName('eatPlace')[tableResEnum].src);
//numResTables = document.getElementsByClassName('eatPlace').src.length;
tableArrayLength = tableArray.length - 1;
for (tableResEnum = 0; tableResEnum <= tableArrayLength; tableResEnum += 1) {
tableSrces = tableArray[tableResEnum].src;
//alert(tableSrcTapped);
if (tableSrces === tableSrcTapped) {
tableArray[tableResEnum].removeEventListener('click', tableUntap);
tableArray[tableResEnum].addEventListener('click', tableTap);
tableArray[tableResEnum].src = window.location + 'resources/tableBase.svg';
} /*else if () {
}*/
}
resTableArray.splice(0, resTableArray.length);
}
Set/Unset a particular table:
tableUntap = function () {
$(this).unbind('click', tableUntap);
$(this).bind('click', tableTap);
this.setAttribute('src', 'resources/tableBase.svg');
resTableArray.shift(this);
};
tableTap = function () {
$(this).unbind('click', tableTap);
$(this).bind('click', tableUntap);
this.setAttribute('src', 'resources/tableTapped.svg');
resTableArray.push($(this).attr('id'));
};
Convert the elements within the 'eatPlace' class to an array:
$('.eatPlace').bind('click', tableTap);
tableList = document.getElementsByClassName('eatPlace');
tableArray = Array.prototype.slice.call(tableList);
Table instantiation:
for (tableEnum = 1; tableEnum <= tableNum; tableEnum += 1) {
tableImg = document.createElement('IMG');
tableImg.setAttribute('src', 'resources/tableBase.svg');
tableImg.setAttribute('id', 'table' + tableEnum);
tableImg.setAttribute('class', 'eatPlace');
tableImg.setAttribute('width', '15%');
tableImg.setAttribute('height', '15%');
$('#tableBox').append(tableImg, tableEnum);
if (tableEnum % 4 === 0) {
$('#tableBox').append("\n");
}
if (tableEnum === tableNum) {
$('#tableBox').append("<div id='subbles' class='ajaxButton'>Next</div>");
$('#tableBox').append("<div id='cazzles' class='ajaxButton'>Cancel</div>");
}
}
First mistake is in tapping and untapping tables.
When you push a Table to your array, your pushing its ID.
resTableArray.push($(this).attr('id'));
It will add id's of elements, depending on the order of user clicking the tables.
While untapping its always removing the first table.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift
resTableArray.shift(this);
So, when user clicks tables 1, 2, 3. And unclicks 3, the shift will remove table 1.
Lets fix this by removing untapped table
tableUntap = function () {
$(this).unbind('click', tableUntap);
$(this).bind('click', tableTap);
this.setAttribute('src', 'http://imgur.com/a7J8OJ5.png');
var elementID = $(this).attr('id');
var elementIndex = resTableArray.indexOf(elementID);
resTableArray.splice(elementIndex, 1);
};
So you were missing some tables after untapping.
Well lets fix tableClear,
You have a array with tapped tables, but you are searching in main array.
function tableClear() {
tableLen = resTableArray.length;
for (var i = 0; i < tableLen; i++) {
var idString = "#" + resTableArray[i];
var $element = $(idString);
$element.unbind('click', tableUntap);
$element.bind('click', tableTap);
$element.attr("src", 'http://imgur.com/a7J8OJ5.png');
}
resTableArray = [];
}
Im searching only tapped tables, and then just untap them and remove handlers.
fiddle: http://jsfiddle.net/r9ewnxzs/
Your mistake was to wrongly remove at untapping elements.
I have got 3 elements (#hotlink1Div, #topBarContentid, #hotlink2Div) which will be in a loop.
I have managed to find the code to get the loop online.
Currently the order in which they are appearing is: #topBarContentid, #hotlink1Div, #hotlink2Div
I would like to see the following order: #topBarContentid, #hotlink1Div, #topBarContentid, #hotlink2Div, #topBarContentid.
slideHotlinks: function () {
console.log(this.px + "Hotlinks started");
var $elements = $('#hotlink1Div, #topBarContentid, #hotlink2Div'); //List of elements used
function hotlinks_loop(index) { //Function to index elements as their are shown
console.log(this.px + "Hotlinks loop created");
$elements.eq(index).slideDown(1000, function() {
var $self = $(this);
setTimeout(function() {
console.log(this.px + "Hotlinks timeout set");
$self.fadeOut(1000);
hotlinks_loop((index + 1) % $elements.length);
},5000);
});
}
hotlinks_loop(0); // start with the first element
How about:
var elements = ['#pointsbarDiv', '#hotlink1Div','#pointsbarDiv', '#hotlink2Div'];
function anim_loop(index) {
$(elements[index]).slideDown(1000, function() {
var $self = $(this);
setTimeout(function() {
$self.fadeOut(1000);
anim_loop((index + 1) % elements.length);
}, 5000);
});
}
anim_loop(0); // start with the first element
Taken from an edit of the original jsbin: http://jsbin.com/uwonun/46
This uses a javascript array rather than a jquery selector. Each entry in the array is converted into a jquery object in the first line of the anim_loop function.
A jquery selector is not quite the same thing as a collection, instead it walks the dom of the page and returns elements that match it's expression, in the order they appear on the page. Therefore it is not possible to get a selector to return the same element twice. In addition id's within a page should be unique, so a selector should only return one element for each id.
I have a table that is created in ASP.NET C# code behind. The table has several levels of groupings, and when I create the rows for the outer most grouping, I add an custom attribute as follows:
foreach (Table2Row row in Table2Data)
{
// skipping a bunch of irrelevent stuff
...
tr_group.Attributes.Add("RowsToToggle", String.Format(".InnerRowGroupId_{0}", row.GroupHeaderId));
...
}
The attribute is the CSS class name of the inner level rows that I would like to toggle. When the user clicks on the outer level row, I would like to call JQuery Toggle function for all inner level rows that match the custom attribute.
To achieve that effect, I have attached an onclick event to the header rows with the following script in the aspx file:
var tableId = '<%= Table2MainTable.ClientID %>';
$(document).ready(function () {
var table = document.getElementById(tableId);
var groupRows = table.getElementsByClassName("Table2GroupHeaderRow");
for (i = 0; i < groupRows.length; i++) {
table.groupRows[i].onclick = function () { ToggleOnRowClick(table.rows[i]); }
}
});
function ToggleOnRowClick(row) {
var r = $('#' + row.id);
var innerRows = r.attr('RowsToToggle');
$(innerRows ).toggle();
}
So, clicking anywhere on the header row should call the function ToggleOnRowClick, which should then toggle the set of rows below it via the custom attribute RowsToToggle.
When I set a (FireBug) break point in the ToggleOnRow function, the variable r appears to be pointing to the correct object. However, innerRows is not getting set but instead remains null. So am I setting the custom attribute incorrectly in ASP.NET or reading in incorrectly in JQuery?
You did not post the code to generate inner level rows, I am assuming you sat proper classes to them.
There are few issues with the jquery you posted. This line wouldn't work:
table.groupRows[i].onclick = function () { ToggleOnRowClick(table.rows[i]); }
You don't have any groupRows property defined for table object.
We don't care about table row anymore, we care about groupRows[i] and want to pass it to ToggleOnRowClick function.
This line in next function is also wrong:var r = $('#' + row.id);
Solution: Change your script to this:
var tableId = '<%= Table2MainTable.ClientID %>';
$(document).ready(function () {
var table = document.getElementById(tableId);
var groupRows = table.getElementsByClassName("Table2GroupHeaderRow");
for (i = 0; i < groupRows.length; i++) {
groupRows[i].onclick = function () { ToggleOnRowClick(this); }
}
});
function ToggleOnRowClick(row) {
//var r = $('#' + row.id);
var innerRows = $(row).attr('RowsToToggle');
$("." + innerRows).toggle();
}
I have tested the code with dummy data. So if you have any issue, PM me.
This line is your culprit:
table.groupRows[i].onclick = function () { ToggleOnRowClick(table.rows[i])
By the time the event handler runs, table.rows might still exist, but i will be set to groupRows.length+1, which is out of bounds for the array. The handler will get called with an argument of undefined.
Remember, Javascript is an interpreted language! The expression "table.rows[i]" will get interpeted when the handler runs. It will use the last value of i (which will still be set to the value that caused your for loop to end, groupRows.length+1).
Just use
table.groupRows[i].onclick = function () { ToggleOnRowClick(this) }
So, First you shouldn't use custom attributes... they are a sin!
Please use data attributes instead, so that is what I'm going to use in the code, should be an easy fix regardless.
If this doesn't work then I'd be very very interested in seeing a dumbed down HTML snippet of the actual output.
$(document).ready(function () {
$('#MYTABLE').on('click', '.Table2GroupHeader', function() {
var attr_if_you_insist_on_sinning = $(this).attr("RowsToToggle");
var data_if_you_like_not_sinning = $(this).data("RowsToToggle");
//if the row is like <tr data-RowsToToggle=".BLAH" or th etc
//asumming you set the attribute to .BLAH then:
var rows_to_toggle = $(data_if_you_like_not_sinning);
rows_to_toggle.toggle();
//assuming you set it to BLAH then:
var rows_to_toggle = $("."+ data_if_you_like_not_sinning);
rows_to_toggle.toggle();
});
});
$(document).ready(function () {
$('#<%= Table2MainTable.ClientID %> .Table2GroupHeader').each(function(){
$(this).click(function(){
$(this).toggle();
});
});
});
I have very simple html page with js code:
<html>
<head>
<title></title>
</head>
<body>
<div id="divButtons">
</div>
<script type="text/javascript">
var arrOptions = new Array();
for (var i = 0; i < 10; i++) {
arrOptions[i] = "option" + i;
}
for (var i = 0; i < arrOptions.length; i++) {
var btnShow = document.createElement("input");
btnShow.setAttribute("type", "button");
btnShow.value = "Show Me Option";
var optionPar = arrOptions[i];
btnShow.onclick = function() {
showParam(optionPar);
}
document.getElementById('divButtons').appendChild(btnShow);
}
function showParam(value) {
alert(value);
}
</script>
</body>
</html>
That page binds 10 buttons, but when you click on any button it always shows alert "option9". How is it possible assign onclick event to show correspondent option !?
Thanks!
You'll have to do something like this:
btnShow.onclick = (function(opt) {
return function() {
showParam(opt);
};
})(arrOptions[i]);
Consider the fact that when the onclick() function is executed, all it has is:
showParam(optionPar);
, verbatim. The optionPar will be resolve at the time the click event is executed, and at this point it most likely be the latest value you assigned to it. You should generally avoid passing variables in such a way.
The problem you are trying to solve is best solved by re-writing the piece such as:
btnShow.value = "Show Me Option";
var optionPar = arrOptions[i];
btnShow.optionPar = optionPar;
btnShow.onclick = function(e) {
// if I'm not mistaking on how to reference the source of the event.
// and if it would work in all the browsers. But that's the idea.
showParam(e.source.optionPar);
}
The accepted answer seems to work, but seems to be confusing and a somewhat cumbersome way to do it. A better way perhaps might be to use the data attribute for the element you're looking to assign the event listener for. It's simple, easy to understand, and way less code. Here's an example:
btnShow.data = arrOptions[i];
btnShow.onclick = function() {
showParam(this.data);
}
I attach an event handler:
window.onload = function() {
var folderElement;
tagFolders = document.getElementById("folders");
for (i = 0; i < folders.length; i++) {
folderElement = folderButtons[i];
folderElement = document.createElement("button");
folderElement.setAttribute("id", folders[i]);
folderElement.setAttribute("type", "button");
folderElement.innerHTML = folders[i];
if (typeof window.addEventListener !== "undefined") {
folderElement.addEventListener("click", getFolderElement, false);
} else {
folderElement.attachEvent("onclick", getFolderElement);
}
tagFolders.appendChild(folderElement);
}
which can retrieve anything from the element that triggered the event:
// This function is the event handler for the folder buttons.
function getFolderElement(event) {
var eventElement = event.currentTarget;
updateFolderContent(eventElement.id);
}
in which case you have to embed the option inside the element / tag. In my case I use the id.
For jquery, check out the adding event data section from the API:
...
for (var i = 0; i < arrOptions.length; i++) {
$('<input id="btn" type="button" value="Show Me Option"><input>').appendTo("#divButtons")
$('#btn').bind("click", {
iCount: i},
function(event) {
showParam(arrOptions[iCount]);
});
}
The accepted answer is correct but I feel that no real explanation was done.
Let me try to explain, the issue here is classical missing closure.
The variable 'i' is getting increased by 1 per loop iteration,
and the on-click event actually is not being executed, whether only applied to the a element, it getting summarize up to the length of arrOptions which is 10.
So, the loop continues up until 'i' is 10,
Then, whenever the on-click event is being triggered, it takes the value of i which is 10.
now, for the solution,
in the solution we are using a closure, so that when we apply the value of 'i' to the on-click event of the a element, it actually gets the exact value of i at in time.
The inner function of the onclick event create a closure where it references the parameter (arrOptions[i]), meaning what the actual i variable is at the right time.
The function eventually closes with that value safely,
and can then return its corresponding value when the on-click event is being executed.
You pass just the reference of the variable to the function, not it's value. So every time the loop is iterated, it assigns a reference to your anonymous function and all of them point to the same value in memory. But since you use the same variable name in the loop, you overwrite the value of the variable. You can concatenate the variable to a string to preserve it's value. For example like that:
btnShow.onclick = new Function("", "showParam(" + arrOptions[i] + ");");
The first parameter is the name of the function but afaik it is optional (it can be left blank or omitted at all).
pp();
function pp()
{
for(j=0;j<=11;j++)
{
if(j%4==0)
{
html+= "<br>";
}
html += "<span class='remote' onclick='setLift(this)' >"+ j+"</span>";
}
document.getElementById('el').innerHTML = html;
}
function setLift(x)
{
alert(x.innerHTML);
}