jquery class selector inside a loop - javascript

I have a simple question about the expression in jquery to select a class which involved a for loop. Basically, I have two steps:
1. Generate some html tables with a loop.
2. Use jQuery to unhide them.
Below is the simplified code to
1. generate html tables (I will add a loop index to separate each loop created tables) :
2. the key part of the second step is to unhide generated tables. My selector is written as: method_options_1'+i+', where i is a for loop index.
for (var i = 2; i <= 5; i++) {
<tr class="method_options_1'+i+'" style="display: none;"><th><label for="id_CAM_1">Chemical application Method (CAM):</label></th>
<td><select name="CAM_1_'+i+'" id="id_1_'+i+'">
<option value="2">2-Interception based on crop canopy</option>
<option value="9">9-Linear foliar based on crop canop</option></select>
</td></tr>
$('.method_options_1'+i).closest('tr').show();
}
However, this selector does not work, which means I could not show the hidden element. While, if I remove the index i from both the HTML and jquery, the selector works. Since I have to keep the i index, can anyone give me some suggestions (I tried to remove closest('tr'), but it does not work)?

'.method_options_1'+i is already a tr, so first try removing the closest('tr') step:
$('.method_options_1'+i).show();
See http://jsfiddle.net/WJDCm/

That's because as far as Javascript is concerned, name is simply a string: method_options_1'+i'. It does not evaluate any code inside that string. If you want to do it correctly, do something like this:
HTML:
<tr class="method_options">etc</tr>
Javascript:
$('.method_options:eq('+i+')').show();
EDIT:
Perhaps I misunderstood. You are generating this inside a Javascript for loop, so i is a valid variable in code space. If that's the case, then you simply have to take out closest(), as it tells jQuery to travel up the DOM and select the first tr that it finds. In this case, that appears to be nothing. You want to work on the tr that you selected, not a tr that is a parent of the one you are selecting.

I really wonder how you run the above code... however doing this does work
HTML:
​<table id='myTable'>
</table>​​​​​​​​
JavaScript:
$(function(){
for (var i = 2; i <= 5; i++) {
$('#myTable').append('<tr class="method_options_1'+i+'" style="display: none;"><th><label for="id_CAM_1">Chemical application Method (CAM):</label></th><td><select name="CAM_1_'+i+'" id="id_1_'+i+'"> <option value="2">2-Interception based on crop canopy</option> <option value="9">9-Linear foliar based on crop canop</option></select> </td></tr>');
$('.method_options_1'+i).closest('tr').toggle('slow');
}
})
Solution

Related

jquery affect all instances of a table id

I have a table that's generated through php. Whenever "bob" is the name of the person who this data belongs to, I generate a tr id to denote that:
<tr id="0bob">...</tr>
<td>...</td>
<tr id="0bob">...</tr>
<tr id="0bob">...</tr>
<tr id="0bob">...</tr>
<tr id="0bob">...</tr>
The data inside each of the tds inside of the trs is different, and the user has to select which of these rows they want, using this checkbox:
print "<input type=\"checkbox\" id=\"check\" data-border=\"$border\" data-z=\"$z\" data-x=\"$x\" data-pn=\"$pn\" value=\"\">";
Then, in my JavaScript, I have the following line which is supposed to dim all of these lines whenever one of the checkboxes in these trs is clicked.
var pn = this.dataset.pn;
var x = this.dataset.x;
//anytime a checkbox with the id 'check' is clicked, (this is every checkbox on the page)
$('input[type="checkbox"][id="check"]').change(function() {
$( "#" + x + PN ).fadeTo( "slow" , 0.7, function() { });
}
The code, in my mind, is accurate - I'm asking for any td with the id of 0bob to be faded to 70%. The issue is that while the code "works," it only fades the first instance of this, then stops, like so:
It always fades the first instance, (red in this example,) regardless of which color the user selects, (blue, pink, or yellow).
I also can't use a tr class because I'm already using the class to change other aspects of the formatting. What am I doing wrong here?
You must use class. Ids must be unique and the browser will get angry if you duplicate them. You can pass multiple classes as follows:
<element id="some-id" class="class1 class2 class3">
From JavaScript classes can be added or removed using classList. JQuery has https://api.jquery.com/addclass/ method.
You should be using data-* attribute since ID is meant to occur once in the document. You can however work around this limitation by using an attribute selector like $('[id=0bob]'). See for example http://jsfiddle.net/Lk7dqbp6/
Your problem is that id attributes must be unique.
And the browser does that: finds the first element with that id and stops there, as it should.
Using repeated ids is invalid HTML and must be avoided like plague.
There are many alternatives for this.
I will only write the HTML structure for this.
Solution 1: a data-* attribute
You already use those, so, just use another one!
<tr data-user="bob"></tr>
These were made with the goal of providing aditional data about an element.
Solution 2: another class
You can have multiple classes per element.
Just make sure they are separated by a space:
<tr class="user-bob another-class more classes"></tr>
This may be harder to use.
Solution 3: another id schema
If you have a primary key on your SQL, you can use it to identify the user:
<tr id="user_bob_0"></tr>
<tr id="user_bob_1"></tr>
<tr id="user_bob_2"></tr>
This may be a bad idea in some situations but it will have all the data ready to use without many troubles.
Outside the scope of the answer, you have another problem:
You have this code:
var pn = this.dataset.pn;
var x = this.dataset.x;
//anytime a checkbox with the id 'check' is clicked, (this is every checkbox on the page)
$('input[type="checkbox"][id="check"]').change(function() {
$( "#" + x + PN ).fadeTo( "slow" , 0.7, function() { });
}
You see the comment?
Same problem: non-unique ids...
For this one, you would be better off using classes.
Instead of
$('input[type="checkbox"][id="check"]')
You would use
$('input.check')
Or
$('.check')
This is the right way to do it.
Also, the performance gain will be HUGE!
Attribute selectors (like [type="checkbox"] and [id="check"]) are one of the slowest selectors!
The only selectors slower than these are the pseudo-element selectors (:before, :after, ::selection, ...).
You can read more here: Is CSS faster when you are specific?
You may be thinking that this won't affect jQuery, but it will.
jQuery uses document.querySelectorAll() which runs a CSS selector in the DOM to select Javascript objects. (When it fails or isn't available, jQuery uses other methods)
Imagine your jQuery looking for over 300 elements for the selector in each of them.
Now imagine a basic table with the classes, where a few elements are connected to an entry.
See the difference?
This is the difference between your code taking 200ms and 30ms (non-measured).

Select a div insinde another div with jQuery

So I try to select a div within another div. My html goes like this:
<div id="Stage_game_page1"><div id="cube0">[...]</div><div id="cube1">[...]</div></div>
I want to select my #cube0 within my Stage_game_page specifically, with jQuery or JS.
The goal of the selection is to use it in an loop.
I tried :
var count =$("#Stage_game_page").children().length;
for(i=0; i<count;i++){
$("#Stage_game_page")$("#cube"+i)[...]
}
I don't understand what I'm doing wrong.
var count =$("#Stage_game_page").children().length;
for(i=0; i<count;i++){
$("#cube"+i);
}
This is sufficient to select the "#cube0"/"#cube1"/"#cube2" etc. especially since ids are always unique. To answer the question $("#cube0", "#Stage_game_page")... that is how you select a div in another div
The id attribute should only be used once! I see above that you're using id="cube0" twice. If you want your divs to be recognized in multiple instances, use a class instead (the . instead of the #). Using the same id twice will probably break your script.
I believe for your html, you could use id "cube0", "cube1", etc., as long as you're ok with entering them manually. That should work for the loop you'd like to use.
Loops through each div that starts with the id cube inside Stage_game_page1
$("#Stage_game_page1 > div[id^='cube']").each(function () {
alert($(this).html());
});
JSFiddle
Child Selctor
Starts with Selector
use each() for loop.
$('#Stage_game_page1').children().each(function(index) {
// your code here with index starts from 0
});
or this using jquery attribute starts with selector
$('#Stage_game_page1').find('[id^="cube"]').each(function(index) {
// your code here
});
You need to use .find() or .children() or the like.
The correct jQuery usage would be
$("#Stage_game_page").find('#cube'+i)
to find a div with that id inside the container #stage_game_page
You have duplicate cube0 in your html code..
and i think the look should contain something like that:
$("#cube"+i)[...]
One another solution is:
$("#Stage_game_page1 div[id='cube0']")

How to clone elements and generate dynamic ids

I am cloning some form elements and want to generate for them dynamic ids so I can acces their content later on, but I don't really know how to do that, I'm a noob with Jquery/Javascript, by the way.
My html:
<tr>
<td>
<label for="ability">Ability</label><br>
<div id="rank_ability" name="rank_ability">
<select name="ability" id="ability">
<option value=""></option>
<option value="hexa">Test</option>
</select><br>
<label for="range_ability_min">Range:</label>
<input type="textbox" name="range_ability_min" id="range_ability_min" class="small_text" value="0" /> -
<input type="textbox" mame="range_ability_max" id="range_ability_max" class="small_text" value="0" /><br>
</div>
Add Ability<br><br>
</td>
</tr>
My JS:
$(document).ready(function () {
var element, ele_nr, new_id;
$('.rank_clone').click( function() {
element = $(this).prev();
ele_nr = $('div[name="'+element.attr('name')+'"]').length;
new_id = element.attr('name') + ele_nr;
element.clone().attr('id', new_id).attr('name', new_id).insertAfter(element);
});
});
I setup a jsfiddle with what I got here: http://jsfiddle.net/xjoo4q96/
Now, I am using .prev() to select the element to clone which leads to those repeated 1 in the id/name attributes, how could I select it in another way (to mention: I really need to use 'this' because I need this little script in like 3 places, so I don't want to write it for an element with a specific id/class).
Also, I am counting only the element with the base name attribute so .lenght yelds 1 all the time, how would I go around counting all of them ? I guess I have to place them in another div or something but I don't know how would I go around couting them even then.
And, at last, how would I go around changing all the name/id attributes of the elements I have in the div ?
I'd appreciate any help. Thanks.
you can put the template in a hidden div like #tmpl, then clone and set the id attr, e.g.
$('#tmpl').children().first().clone().appendTo('#target').attr('id', 'the_generated_id');
Update
Demo of the template way: http://jsfiddle.net/xjoo4q96/1/, though it would be quite easy to adjust the code to clone the first component that already existed.
BTW, principally, id should be unique, thus the sub-element in the cloned component should use other attribute, like class or certain data- attribute, like those used in the updated fiddle.
Also you might want to call event.preventDefault() as you're clicking an <a>
You are searching already with the wrong name, since it still has the number attached. So delete it first, search for element which have a name attribute starting with this name and then use this base name to create a new one.
$(document).ready(function () {
var element, ele_nr, new_id, base_name;
$('.rank_clone').click( function() {
element = $(this).prev();
base_name = element.attr('name').replace(/[0-9]/g, '');
ele_nr = $('div[name^="'+base_name+'"]').length;
new_id = base_name + ele_nr;
element.clone().attr('id', new_id).attr('name', new_id).insertAfter(element);
});
});
And to answer your last question: you can not go around changing all ids of inner elements, it would be invalid HTML. In principal you can do the same with every id, like adding a number. If you have to do the same with all the name attributes depends on what you want to do exactly. If you have to distinguish between the first and second input, which I suggest, you have to change them too.
try to use cloneJs, it's clone ids, names input, and parametre inside functions ids of input must be like id_foo_1, id_foo_2 ,,,, and name be like inputName[0][foo], inputName[1][foo] https://github.com/yagami271/clonejs

calling one javascript function affecting two html drop download list

My question is can you call just one javascript function and affect two html drop down list the idea is to use the codes below
javascript code:
document.getElementsByClassName("cmbRecom")
html code:
<Select name="drop1" class="cmbRecom" >
<option>Check Fields</option>
</Select>
<Select name="drop2" class="cmbRecom" >
<option>Check Fields</option>
</Select>
what is in my head, is the css behavior where you can name html elements with the same class names and all will follow that style that is declared for that class.
Yes, you can. One possible way is as follows:
document.documentElement.cmbRecomb;
When selecting elements using the function getElementsByClassName the code should work with the returned elements as an array, which will require iteration through the selected elements.
var selects = document.getElementsByClassName("cmbRecom"); //was cmbField
for(var i = 0; i < selects.length; i++){
selects[i].style.width = "200px";
}
Note: The class name and selector were different.
JS Fiddle: http://jsfiddle.net/LWxcX/

How can I jump to the next cell in a table?

I have a table wherein the first column is a checkbox and the second one has a text.
Whenever, the checkbox is checked, I want to know the corresponding value which is in the next cell.
Please tell me how to do.
If I use the getelementsbytagname function, it returns from the start of the document.
This is quite simple to do without jquery. We have a input inside a td so we can go up a level and get the next sibling:
var nextTd = myInput.parentNode.nextSibling;
Because some browser insert empty text nodes between tds we can do the following to make sure we're on the right node:
if (nextTd.tagName != "TD")
nextTd = nextTd.nextSibling;
Also, FWIW, getElementsByTagName can be called from any Node. Thus, if I have a table, I can call
myTable.getElementsByTagName("tr");
To return all rows inside of myTable.
Assuming you're using jQuery (or some other civilized framework), it's pretty easy:
$('table#yourTableId input:checkbox').click(function(ev) {
if (this.checked) {
// not sure what you mean by "want to know" ...
console.log($(this).closest('tr').find('td:nth-child(2)').html());
}
});
You could do it with the jQuery "live" event facility similarly, which'd be cheaper if there are a lot of checkboxes.
The simplest way would be yo use jQuery or a similar library, that implements CSS3 selectors.
$('table input:checked').parent().parent().find('td.nth-child(2)').text():
You could also bind onto the change events of the checkboxes
$('input:checkbox').change = function(){
val = $(this).parent().parent().find('td.nth-child(2)').text():
}

Categories

Resources