While loop in jquery of dynamic id and class - javascript

I have have multiple divs' with similar code within it, but also has a unique id within the main div that calls a toggleClass & slideToggle function. I'm trying to create a loop so that I do not have to write similar code for each element.
--- working code --- (where numeric value after the id would change)
$('#er1').click(function() {
$('#er1').toggleClass('but-extra-on');
$('#cr1').toggleClass('but-closerow-on');
$('#er1').next('div').slideToggle('slow');
return false;
});
-- not working code -- (I want to have functions for the click of #er1, #er2, #er3 etc.)
var count = 1;
while (count < 10){
var curER = 'er'+count;
var curCR = 'cr'+count;
$('#'+curER).click(function() {
$('#'+curER).toggleClass('but-extra-on');
$('#'+curCR).toggleClass('but-closerow-on');
$('#'+curER).next('div').slideToggle('slow');
});
count++;
}
* for some reason, when I use the while code, whenever I click #er1, #er2, #er3 etc.. only the event for #er9 toggles.

You can solve this problem, by using the $(this) selector for the one that you are clicking, and attaching an html data attribute to the div, specifying the other div that you want to change when you click it and selecting the other one with that... make sense.. probably not? Check out Solution 1 below.
The second solution is to use jQuery Event Data to pass the count variable into the event listener.
Solution 1: http://jsfiddle.net/Es4QW/8/ (this bloats your html a bit)
Solution 2: http://jsfiddle.net/CoryDanielson/Es4QW/23/
I believe the second solution is slightly more efficient, because you have slightly less HTML code, and the $(this) object is slightly smaller. Creating the map and passing it as event data, I believe, is less intensive... but... realistically... there's no difference... the second solution has cleaner HTML code, so you should use that.
Solution 3 w/ .slideToggle(): http://jsfiddle.net/CoryDanielson/Es4QW/24/
Edit: Updated solutions by passing in the selected elements instead of the selectors. Now each click event will not do a DOM lookup as it did before.

I've run into this problem before. I fixed it by extracting the event listener code into its own function like so:
for (var i = 1; i < 10; i++) {
attachClickEvent('er'+i, 'cr'+i);
)
function attachClickEvent(cr, er)
{
$('#'+er).click(function() {
$(this).toggleClass('but-extra-on');
$('#'+cr).toggleClass('but-closerow-on');
$(this).next('div').slideToggle('slow');
});
}

Related

Passing parameter to javascript onclick without using HTML

I can't figure this out. I'm trying to create an onclick handler purely in Javascript.
What I plan to do here is inside this DIV, have a collection of items that I can click on. For now, these items will be numbers from 0 to 9 inclusive. When a number is clicked on, a system message consisting solely of that number should pop-up on the screen. I narrowed my problem down to just the onclick handler definition.
If I use this format:
item[n].onclick=function(n){
handler(n);
}
The handler will fire only when click a number which is correct, but the message that appears is something about mouse event.
If I use this format:
item[n].onclick=function(){
handler(n);
}
The handler will pass a value of -1 which in turn is printed as a message. I think it means "false".
How do I modify this:
item[n].onclick=function(){
handler(n);
}
so that 'n' being used as the handler parameter is the same as the number I click on the screen?
My code is the following:
<div ID="Itemset"></div>
function handler(n){
alert(n);
}
collections=document.getElementById('Itemset');
for(n=0;n<10;n++){
item[n]=document.createElement('DIV');
item[n].innerHTML=n;
collections.appendChild(item[n]);
item[n].onclick=function(n){
handler(n);
}
}
What I'm effectively trying to do if you want to understand it HTML wise is this:
<div ID="Itemset">
<div onclick="handler(0);">0</div>
<div onclick="handler(1);">1</div>
<div onclick="handler(2);">2</div>
<div onclick="handler(3);">3</div>
<div onclick="handler(4);">4</div>
<div onclick="handler(5);">5</div>
<div onclick="handler(6);">6</div>
<div onclick="handler(7);">7</div>
<div onclick="handler(8);">8</div>
<div onclick="handler(9);">9</div>
</div>
Except that I don't want to write out onclick="handler(n);" a million times.
Any advice? and feel free to point to another resource that has the answer I need if there is one.
UPDATE
I'm looking for something compatible with older browsers as well. I'm going to have to not go for the bind function because according to mozilla docs, it works for IE 9+. I'm looking for something that works for IE 7+ as well as other browsers. I might have to go for event listeners if there is no other alternative.
You have a closure issue here (see JavaScript closure inside loops – simple practical example), a simple solution is to use bind to use the current value of n to be a parameter of the handler function
item[n].onclick=handler.bind(item[n],n);
U can use addEventListener and ID for find clicked element...
document.getElementById("Itemset").addEventListener("click", function(e) {
// e.target is the clicked element!
// If it was a list item
var value_data = parseInt(e.target.textContent);
if(e.target && value_data > -1) {
alert("Malai test:: "+value_data);
//handler(value_data);
}
});
https://jsfiddle.net/malai/tydfx0az/
I found my answer here: https://bytes.com/topic/javascript/answers/652914-how-pass-parameter-using-dom-onclick-function-event
Instead of:
item[n].onclick=function(n){
handler(n);
}
I have to do:
item[n].onclick=new Function('handler('+n+')');
Funny thing is, the word function needs to be capitalized when making a new instance. It's awkward I have to go this route but it works in IE 7+
One alternative is :
function handler(){
alert(this.id);
}
function myFunction() {
var item=[];
collections=document.getElementById('Itemset');
for(n=0;n<10;n++){
item[n]=document.createElement('DIV');
item[n].innerHTML=n;
item[n].setAttribute("id","itemset"+n);
collections.appendChild(item[n]);
item[n].onclick=handler;
}
}
Insert dynamic ids to the elements and when you click on any element retrieve its id using this.id and do whatever you want to do with that value.
That's all.
Hope this helps.

Javascript interchange with command button

I am trying to setup an interchange using two texts boxes with a command button in between.
The idea is you type a reference/code in the left hand text box, click the button and it generates an alternative reference/code in the right hand text box.
The point being the user can check alternate bearing references if they can't find what they are looking for with the one they have.
The code I use so far is:
<script type="text/javascript">
oldRef = new Array ("Z582","T608","A173");
newRef = new Array ("C850","S708","X449");
function convert()
{
document.getElementById("v2").value = "";
for (index=0 ; index < oldRef.length ; index++)
{
if ( document.getElementById("v1").value == oldRef[index] )
document.getElementById("v2").value = newRef[index];
}
}
</script>
V1 and V2 refer the the text box ID.
This works with the text boxes but I don't know how to incorporate the command button into this so that they need to click the button in the middle for it to generate.
Any suggestions would be much appreciated.
Best
Will
Its pretty Easy stuff what you need to do is to use onclick of the button like this
document.getElementById('button').onclick = function () {
document.getElementById("v2").value = "";
for (var index=0 ; index < oldRef.length ; index++) {
if (document.getElementById("v1").value == oldRef[index])
document.getElementById("v2").value = newRef[index];
}
}
Here is a demo
I hope this is waht you want....
So essentially there are two things that you need to accomplish what you asked. You need to create a element within your HTML, in this case a button. You then need to catch the event that you want to catch from that element and then execute you convert function.
This is one example of accomplishing this:
So create an button within your HTML
<button id="btn_command">Command</button>
Then in Javascript you want to target that button and add an event listener to that button. In the example the below the variable var btnCommand is set to the html button by using the getElementById method to get that button with that id. Then we add and event listener to that element that when clicked it executes your convert function.
var btnCommand = document.getElementById ("btn_command") ;
btnCommand.addEventListener("click", convert, false) ;
If you want to use jQuery you would do something like this.
$('#btn_command').on('click', function() { convert(); });
Here is another quick and dirty way to just test you button with your function. It is not a best idea to mix your javascript inline with your html but just to test your button and if your convert function is doing that you think you could just say
<button onClick="convert()">Command</button>
Well there are few ways to accomplish what you asked. Happy Coding!

jquery checkbox slow, not sure how to fix

I have used firebug and IE profilers and can see what function in my code is causing the slowness. Being new to jquery, the recommendations that I have read online are not clear to me. I have made an example page that shows the slow behavior when you check or uncheck a check box. No surprise that this is fast using Chrome.
The function that is slow can be found on line 139.
$('.filters input').click( function()
JSFiddle can be found here
The code is 122 KB and can be found here
UPDATE: if you know of any examples online that are similar in function and faster, please share.
i had a brief look through your code, but it was very hard to follow. it seemed as if you were looping through things many many times. i used a much simpler approach to get the list of all states.
your approach was
* make a massive string which contained every class (possibly repeated multiple times)
* chop it up into an array
* loop through the array and remove duplicates
i simply took advantage of the fact that when you select something in jQuery you get a set rather than a single item. you can therefore apply changes to groups of object
$(document).ready(function () {
//this will hold all our states
var allStates = [];
//cache filterable items for future use
var $itemsToFilter = $(".filterThis");
//loop through all items. children() is fast because it searches ONLY immediate children
$itemsToFilter.children("li").each(function() {
//use plain ol' JS, no need for jQuery to get attribute
var cssClass = this.getAttribute("class");
//if we haven't already added the class
//then add to the array
if(!allStates[cssClass]) {
allStates[cssClass] = true;
}
});
//create the container for our filter
$('<ul class="filters"><\/ul>').insertBefore('.filterThis');
//cache the filter container for use in the loop
//otherwise we have to select it every time!
var $filters = $(".filters");
// then build the filter checkboxes based on all the class names
for(var key in allStates) {
//make sure it's a key we added
if(allStates.hasOwnProperty(key)) {
//add our filter
$filters.append('<li><input class="dynamicFilterInput" type="checkbox" checked="checked" value="'+key+'" id="filterID'+key+'" /><label for="filterID'+key+'">'+key+'<\/label><\/li>');
}
}
// now lets give those filters something to do
$filters.find('input').click( function() {
//cache the current checkbox
var $this = $(this);
//select our items to filter
var $targets = $itemsToFilter.children("li." + $this.val());
//if the filter is checked, show them all items, otherwise hide
$this.is(":checked") ? $targets.show() : $targets.hide();
});
});
FIDDLE: http://jsfiddle.net/bSr2X/6/
hope that's helpful :)
i noticed it ran quite a bit slower if you tried to slideup all the targets, this is because so many items are being animated at once. you may as well just hide them, since people will only see the ones at the top of the list slide in and out of view, so it's a waste of processor time :)
EDIT: i didn't add logic for show all, but that should be quite a trivial addition for you to make if you follow how i've done it above
You could use context with your selector:
$('.filters input', '#filters_container').click(function()...
this limits the element that jQuery has to look in when selecting elements. Instead of looking at every element in the page, it only looks inside your $('#filters_container') element.

Problem with JS, DOM and looping

I have a problem with JavaScript looping and DOM.
so I have a few div's, each has a background image defined by CSS, however when i rollover a text link, i wish for these background images to change, which ones will change depends on their class name and the link mouseover'ed
<div id="im1" class="web"></div>
<div id="im2" class="logo"></div>
<div id="im3" class="web"></div>
<div id="im4" class="logo"></div>
<div id="5" class="logo"></div>
web
so those are the divs with my link for the mouse over.
then to change these images i have some simple JavaScript, which works fine (if very long)....
function showweb() {
document.getElementById("im1").style.backgroundImage = "url('back/1col.png')";
document.getElementById("im2").style.backgroundImage = "url('back/2col.png')";
however, i wondered if there was a way i would condition by class name, and only change those with a certain class name, eg web, or logo. ive tried various ways and loops and things, but none seemed to work.
e.g
function showweb() {
for(i=0; i=5; i++){
url = "im" + i;
if(document.getElementById("url").className=="web"){
document.getElementById("url").style.backgroundImage = "url('back/"+ i +"col.png')";}
}
}
however this doesn't work, the divs just don't change..... am i doing something wrong? missing something? or doing it the completely wrong way?
all help appreciated, thanks in advance.
Edit: changed the "url" to url, my bad, that was very foolish, however still didnt work. i will try a few other ideas posted.
thanks everyone so far.
You don't need the quotes around url:
document.getElementById(url)
This may work (if the link to your images is right and presumed that by id="5" you mean id="im5". Play with it until it's right. Check your code thourougly, there were several errors (typos or worse 1) in your coding:
function showweb() {
for(var i=1; i < 6; i++){
var el = document.getElementById("im"+(i));
if(el && /web/.test( (el ||{}).className)){
el.style.backgroundImage = "url(back/"+ i +"col.png)";}
}
}
1 a few notes on that
id = "5" should supposedly be id ="im5"
i=0; i=5; i++ => i=5 should be i<5
i=0; i=5; i++ creates a global variable i. Use var i=0;...
given your id's, you should start with var i = 1
though not a real error, you don't need to surround the url value with apostrophes
to optimize call document.getElementById once and use it's result in the rest of the code
You're building the "url" variable, but then you pass the string constant "url" into the "getElementById()" function.
To get only elements of the desired class, you need node.getElementsByClassName('your_class'), where node can be document or some <div> selected by id, or any other node of the DOM tree.
Note: Remember that all methods that start with getElement will return single element, and those with getElements will return an array of elements, so this one returns an array which you need to iterate (even if there is only one element in it)
However, since you are working with DOM elements in JavaScript, you would save tons of time by using jQuery
You have a few of problem. First, you have quotes around the variable "url" so it's looking for an element with that id, which doesn't exist and thus fails when you attempt to access the className of a null lookup result. Second, your loop starts at 0, not one and you don't have a div with id "im0" so it would fail anyway when you attempt to get the className of that element, which also doesn't exist. Third, the check in your loop sets i to 5 instead of checking if it is less than or equal to 5. Your loop with thus continue forever, since 5 equates to true, which I'm sure is not what you want. Fourth, your code may break if you assign additional classes to the elements. Lastly, most of this sort of thing has already been done for you -- might I suggest you look into using a javascript framework, such as jQuery -- with the hover() method, as a better alternative than re-inventing the wheel if this isn't purely a learning exercise.

Toggle effect problem when using for-loop in IE7

I'm a webdesigner that's trying to get the hang of JavaScript and jQuery, and I want to learn how to write shorter, more concise code - to avoid being ridiculed by the developers at work ;)
I have this snippet:
// toggle divs when checkbox is checked
$('.product-optional-checkbox1').click(function () {
$('.product-optional-toggle1').toggle('fast');
});
$('.product-optional-checkbox2').click(function () {
$('.product-optional-toggle2').toggle('fast');
});
$('.product-optional-checkbox3').click(function () {
$('.product-optional-toggle3').toggle('fast');
});
// hide divs
$('.product-optional-toggle1').hide();
$('.product-optional-toggle2').hide();
$('.product-optional-toggle3').hide();
...that I want to reduce using a for-loop, like this:
for( var i = 1; i < 4; ++i ) {
$('.product-optional-checkbox' + i).click(function () {
$(this).parent('div').find('div').toggle('fast');
});
$('.product-optional-toggle' + i).css({ display: 'none'});
};
It works fine in FF, however in IE7 it toggles twice. Anyone know who to solve a problem like this?
It's hard to say without seeing the HTML structure but maybe going to the parent then descendants is finding multiple divs?
In your example, you could replace:
$(this).parent('div').find('div').toggle('fast');
With code more similar to the original examples:
$('.product-optional-toggle' + i).toggle('fast');
However, it would be much better to ditch all the numbers and just use a class of .product-optional-checkbox. This way you can add a click function to all elements of that class in one go and avoid the loop:
$('.product-optional-checkbox').click(function () {
// do stuff using $(this)
});
Given that your click events seem to be tied to checkboxes (based on the class names you have in your example), why not actually provide code to handle click events for those checkboxes? For example:
<div id='my_group_of_checkboxes'>
<input type="checkbox" id="checkbox1">
<input type="checkbox" id="checkbox2">
...
</div>
And your jQuery code is then stripped down to three lines:
$('#my_group_of_checkboxes :checkbox').click(function(){
$(this).parent('div').hide('fast');
});
You also seem to need to hide the <div> elements related to each checkbox:
$('div[class^="product-optional"]').hide();
Although ID selectors would be a better option here and, depending on their position within your page, you may even be able to get away with something like:
$('#my_container_div_id div').hide();
If you can post some of your HTML, that might help provide more accurate answers as well.

Categories

Resources