How can I check if the current element in a .each loop is the last element in a selection?
I have tried it with the following code:
$('#order').find('.xyz').find('input[id ^="order"]').not('[id $="_zyx"]').each(function (index, element) {
var isLast = ($(element) == $('#order').find('.xyz').find('input[id ^="order"]').not('[id $="_zyx"]').last());
});
With the query I am getting three elements. And I want to select the last element of this selection for further use.
In order to determine which element is the right one I have tested it with the code above but I am getting false for isLast for the last element where it should be true.
Am I missing something?
You don't need to use Jquery for this.
Use the length of your elements and the index of your loop.
var elements = $('#order').find('.xyz').find('input[id ^="order"]').not('[id $="_zyx"]');
elements.each(function (index, element) {
var isLast = (index+1) === elements.length;
});
It would be helpful to see your HTML, but you should just be able to use the last selector:
https://api.jquery.com/last-selector/
Related
I have the following code that is working correctly to insert a success span after an input field when a correct value is entered. But my problem is that it adds the span every time I leave the field. From question Jquery insertAfter only once if element exist I know that I could set the ID of the span when created and check the length each time the event fires to see if it already exists. But am not sure how to do that when using a class to select the fields.
Any help with class selectors would be helpful.
$(".systemFieldName").blur(function(){
var val = $(this).val();
var exists = $.inArray(val,allFields);
if (val!="" && exists>=0){
$("<span class='label label-success'>Valid</span>").insertAfter(this).one();
}
});
This should help.
allFields=["121",'test'];
$(".systemFieldName").blur(function(){
var val = $(this).val();
var exists = $.inArray(val,allFields);
//See if the next element is a span with class label.
var nextEl=$(this).next(); //next element
var add=true; //add by default
if(nextEl.hasClass('label-success')) add=false; //don't add.
if (val!="" && exists>=0 && add){ //only insert if all conditions are true.
$("<span class='label label-success'>Valid</span>").insertAfter(this).one();
}else if((val == "" || exists < 0) && !add) { // The !add means there is already the Valid span, we can safely remove nextEl, if the value changes.
nextEl.remove();
}
});
https://jsfiddle.net/ym66f48p/2/
This checks to make sure the next element is a span, it also includes a remove function that if the value is altered later on, it will remove the valid span, but ONLY if the next element is already a valid span.
use 121 or test as your testing in the jsFiddle.
Try this fiddle: https://jsfiddle.net/8jpc74z8/
All I am doing here is to check whether there is any sibling to the systemFieldName already added. If not, then add.
if($(".systemFieldName +.label-success").length === 0){
I am trying to create a loop which is reponsible to delete DOM elements (one or severals lines into an HTML table) :
<tr class="entireLine><input type="checkbox"></tr>
<tr class="entireLine><input type="checkbox" checked></tr>
<tr class="entireLine><input type="checkbox" checked></tr>
JS
for (var i=0; i<$(".entireLine").length; i++){
// Get the current line of the table
var currentLine = $(".entireLine")[i];
// Get the checkbox in the DOM element
var checkbox = $(currentLine).find("input[type=checkbox]");
// Check the state of the checkbox. If checked, remove the line.
if ( $(checkbox).is(":checked") ) {
$(currentLine).remove();
}
}
This code works fine only when there is one line selected. From 2 lines selected, the second line is not deleted because the index (i) is not good after the first remove.
Where is my mistake ?
You can just find tr with checked checkboxes
$(".entireLine").has('input[type=checkbox]:checked').remove()
In your loop the problem is the expression $(".entireLine").length is evaluated in each iteration, it will reduce the length if item was removed in the previous iteration but the value of i is not reduced so there will be some leftout items
.has()
:checked
Use a jquery each:
$(".entireLine").each(function( index ) {
if ($(this).find("input[type=checkbox]").is(":checked")) {
$(this).remove();
}
});
And correct your HTML, it's not <tr class="entireLine> but <tr class="entireLine"> (You forget the closing ")
Reverse your thinking - instead of looping through all the rows to find selected items, find the selected items then remove their rows:
$(":checkbox:selected").each(function() {
$(this).closest("tr").remove();
});
I would do something like this, instead of doing the for loop. This will find all the checkboxes, and do a $.each and if they are checked, it will remove them. I put checkboxes in its own var for debugging purposes.
var checkboxes = $('input[type=checkbox]');
checkboxes.each(function(){
var $checkbox = $(this);
if ( $checkbox.is(":checked") ) {
$checkbox.remove();
}
})
I have the following code and I am trying to remove dynamically all the "container" elements from an element supercontainer dynamically.Since nodeList is live the following code should remove the container1 as well as container2 but it isn't.Can any one tell why?how do I improve this code so as to dynamically remove all childNodes?
<html><body></body>
<script type="text/javascript">
var supercontainer=document.createElement("div");
var container2=document.createElement("div");
var container1=document.createElement("div");
var b=document.createElement("div");
var c=document.createElement("div");
var d=document.createElement("div");
b.appendChild(document.createTextNode("book1"));
c.appendChild(document.createTextNode("book2"));
d.appendChild(document.createTextNode("book3"));
container1.appendChild(b);
container1.appendChild(c);
container1.appendChild(d);
container2.appendChild(document.createTextNode("i am container2"));
supercontainer.appendChild(container1);
supercontainer.appendChild(container2);
document.body.appendChild(supercontainer);
function removeContainers(){
var j=0;
for(i=0;i<supercontainer.childNodes.length;i++){
supercontainer.removeChild(supercontainer.childNodes[j]);
}
}
removeContainers();
</script>
</html>
In your loop,
i = 0; then nodes.length is 2
first item is removed then i becomes 1 and length becomes 1
the loop terminating condition fails
The solution is to keep the loop count in a separate counter variable like length
Use
function removeContainers(){
var j=0, len = supercontainer.childNodes.length;
for(i=0;i<len;i++){
supercontainer.removeChild(supercontainer.childNodes[j]);
}
}
Demo: Fiddle
Because your loop is missing elements.
In the first iteration, you remove the element that is first in the NodeList. As you said, NodeList's are live, so this element is removed from the NodeList you're iterating over as well. This shifts the element that was [1]'st to [0]th.
The loop then increments i to [1], so you ignore the element that is now 0 in the list.
Instead;
while (supercontainer.childNodes.length) {
supercontainer.removeChild(supercontainer.childNodes[0]);
}
I have the following javascript/jquery code, the purpose of which is to -
Deselect a previously selected item from the list, if the selected item value exists in an array
Hide/display each list item dependent on whether they exist in the array
var list = $(row).find("select > option")
var selectedValue = $(row).find("select > option:selected")
if (selectedValue) {
if ($.inArray(selectedValue[0].value, dependencyListItemValues) == -1) {
alert('deselect');
$(selectedValue).attr("selected", false);
}
}
$(list).each(function () {
var value = this.value;
if (value != "") {
if ($.inArray(value, dependencyListItemValues) > -1) {
alert('show');
$(this).show();
}
else {
alert('hide');
$(this).hide();
}
}
});
This is working fine in chrome and firefox, but not in IE9. When running in IE, the alert lines are hit, but the following lines seemingly do nothing:
$(selectedValue).attr("selected", false);
$(this).show();
$(this).hide();
Do I need to use alternative code so this will work in IE?
First: You can use
list.each
instead of $(list).each.
Second, you cannot hide an OPTION element in crossbrowser way.
So, you must remove it (for hide) and re-create it (for show).
You can store all options (and them parent) in array, like so:
var cache_options= [];
list.each(function(index) {
cache_options.push({el:$(this), parent:$(this).parent()});
});
and after
for(var i = 0; i<cache_options.length; i++) {
var value = cache_options[i].el[0].value;
if (value != "") {
if ($.inArray(value, dependencyListItemValues) > -1) {
cache_options[i].parent.append(cache_options[i].el);
}
else {
cache_options[i].el.remove();
}
}
}
Tested!
OK my solution was as follows ... this is based on the answer by meder (thanks!) on this question - Hide select option in IE using jQuery
Firstly, in place of this line:
$(selectedValue).attr("selected", false);
I did this:
$(row).find("select")[0].selectedIndex = -1;
And to show/hide the relevant list items, I had to first wrap those that I needed to hide in a span and then apply the .hide() command, and for those I needed to display, replace the span with the original option element:
//first we need to hide the visible list values that are not in the list of dependent list values.
//get the list values which are currently displayed, these will be the 'option' elements of the 'select' element (list).
//the hidden values are within a span so will not be picked up by this selector
var displayedListValues = $(row).find("select > option")
//loop through the displayed list values
$(displayedListValues).each(function () {
//get the value from this 'option' element
var displayedValue = this.value;
//ignore empty values (first blank line in list)
if (displayedValue != "") {
//if the value is not in the list of dependent list values, wrap in span and apply .hide() command
if ($.inArray(displayedValue, dependencyListItemValues) == -1) {
$(this).wrap('<span>').hide();
}
}
});
//now we need to display the hidden list values that are in the list of dependent list values.
//get the list values which are currently hidden, these will be the 'span' elements of the 'select' element (list).
//the visible values are within an 'option' so will not be picked up by this selector
var hiddenListValues = $(row).find("select > span")
//loop through the hidden list values
$(hiddenListValues).each(function () {
//find the 'option' element from this 'span' element and get its value
var opt = $(this).find('option');
var hiddenValue = opt[0].value;
//ignore empty values (first blank line in list)
if (hiddenValue != "") {
//if the value is in the list of dependent list values, apply .show() command on the 'option' element
//(not sure why the .show() command works in this case?)
//and then replace the 'span' element with the 'option' element, which is effectively removing the span wrapper
if ($.inArray(hiddenValue, dependencyListItemValues) > -1) {
$(opt).show();
$(this).replaceWith(opt);
}
}
});
Which works fine ... although rather annoying I had to do this rather messy re-coding just because IE doesn't support .show() and .hide() of list values!!!!!
Here is a good solution:
http://ajax911.com/hide-option-elements-jquery/
I'm looking to find the id of the previous button. It is pretty far away - lots of table rows, tables, divs, etc. between the target and the button but I thought this would still work:
alert( $(this).prevAll("input[type=button]").attr('id') );
Unfortunately this returns alerts 'undefined'. Help?
function getPrevInput(elem){
var i = 0,
inputs = document.getElementsByTagName('input'),
ret = 'Not found';
while(inputs[i] !== elem || i >= inputs.length){
if(inputs[i].type === 'button'){
ret = inputs[i];
}
i++;
}
return (typeof ret === 'string') ? ret : ret.id;
}
That probably isn't the most efficient solution, but it's the only one I can think of. What it does is goes through all the input elements and finds the one right before the one you passed into the function. You can use it like this, assuming you're calling it correctly and this is the input element:
getPrevInput(this);
Demo
That kind of lookup might be expensive. What about doing a select for all your input[type=button] elements, and traversing that array until you find the element matching your id. Then you can simply reference the array index - 1 to get your answer.
Is the previous button a sibling of the current button? If not, prevAll() won't work. The description of prevAll():
Get all preceding siblings of each element in the set of matched elements, optionally filtered by a selector.
Depending on your DOM structure, you can use a combination of parents() and then followed by find().
This function looks up all input[type=button] elements and uses the jQuery index function to find your current element in this group.
If it could be found and there is a previous element it is returned.
$.fn.previousElem = function(lookup){
var $elements = $(lookup),
index = $elements.index(this);
if(index > 0){
return $elements.eq(index-1)
}else{
return this;
}
}
HTML:
<div><div><div><div>
<input type=button id=1 value=1 />
</div></div></div></div>
<div><div><div><div>
<input type=button id=2 value=2 />
</div></div></div></div>
JS:
alert ($("#2").previousElem('input[type=button]').attr('id'))
http://jsfiddle.net/SnScQ/1/
Here's a different version of Amaan's code, but jqueryfied and his solution wasn't looking for a button. The key to the solution is that jQuery returns the elements in document order, as do document.getElementsByTagName and similar functions.
var button = $('#c');
var prevNode;
$("input[type=button]").each(function() {
if (this == button[0]) {
return false;
}
prevNode = this;
});
alert(prevNode && prevNode.getAttribute('id'));
http://jsfiddle.net/crFy6/
have you tried .closest? ...
alert( $(this).closest("input[type=button]").attr('id') );