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') );
Related
I am wanting something similar to this person, except the element I want to match might not be a direct sibling.
If I had this HTML, for example,
<h3>
<span>
<b>Whaddup?</b>
</span>
</h3>
<h3>
<span>
<b>Hello</b>
</span>
</h3>
<div>
<div>
<img />
</div>
<span id="me"></span>
</div>
<h3>
<span>
<b>Goodbye</b>
</span>
</h3>
I would want to be able to do something like this:
var link = $("#me").closestPreviousElement("h3 span b");
console.log(link.text()); //"Hello"
Is there an easy way to do this in jQuery?
EDIT: I should have made my specification a little bit clearer. $("#me") may or may not have a parent div. The code should not assume that it does. I don't necessarily know anything about the surrounding elements.
var link = $("#me").closest(":has(h3 span b)").find('h3 span b');
Example: http://jsfiddle.net/e27r8/
This uses the closest()[docs] method to get the first ancestor that has a nested h3 span b, then does a .find().
Of course you could have multiple matches.
Otherwise, you're looking at doing a more direct traversal.
var link = $("#me").closest("h3 + div").prev().find('span b');
edit: This one works with your updated HTML.
Example: http://jsfiddle.net/e27r8/2/
EDIT: Updated to deal with updated question.
var link = $("#me").closest("h3 + *").prev().find('span b');
This makes the targeted element for .closest() generic, so that even if there is no parent, it will still work.
Example: http://jsfiddle.net/e27r8/4/
see http://api.jquery.com/prev/
var link = $("#me").parent("div").prev("h3").find("b");
alert(link.text());
see http://jsfiddle.net/gBwLq/
I know this is old, but was hunting for the same thing and ended up coming up with another solution which is fairly concise andsimple. Here's my way of finding the next or previous element, taking into account traversal over elements that aren't of the type we're looking for:
var ClosestPrev = $( StartObject ).prevAll( '.selectorClass' ).first();
var ClosestNext = $( StartObject ).nextAll( '.selectorClass' ).first();
I'm not 100% sure of the order that the collection from the nextAll/prevAll functions return, but in my test case, it appears that the array is in the direction expected. Might be helpful if someone could clarify the internals of jquery for that for a strong guarantee of reliability.
No, there is no "easy" way. Your best bet would be to do a loop where you first check each previous sibling, then move to the parent node and all of its previous siblings.
You'll need to break the selector into two, 1 to check if the current node could be the top level node in your selector, and 1 to check if it's descendants match.
Edit: This might as well be a plugin. You can use this with any selector in any HTML:
(function($) {
$.fn.closestPrior = function(selector) {
selector = selector.replace(/^\s+|\s+$/g, "");
var combinator = selector.search(/[ +~>]|$/);
var parent = selector.substr(0, combinator);
var children = selector.substr(combinator);
var el = this;
var match = $();
while (el.length && !match.length) {
el = el.prev();
if (!el.length) {
var par = el.parent();
// Don't use the parent - you've already checked all of the previous
// elements in this parent, move to its previous sibling, if any.
while (par.length && !par.prev().length) {
par = par.parent();
}
el = par.prev();
if (!el.length) {
break;
}
}
if (el.is(parent) && el.find(children).length) {
match = el.find(children).last();
}
else if (el.find(selector).length) {
match = el.find(selector).last();
}
}
return match;
}
})(jQuery);
var link = $("#me").closest(":has(h3 span b)").find('span b').text();
I'd like to select an element using javascript/jquery in Tampermonkey.
The class name and the tag of the elements are changing each time the page loads.
So I'd have to use some form of regex, but cant figure out how to do it.
This is how the html looks like:
<ivodo class="ivodo" ... </ivodo>
<ivodo class="ivodo" ... </ivodo>
<ivodo class="ivodo" ... </ivodo>
The tag always is the same as the classname.
It's always a 4/5 letter random "code"
I'm guessing it would be something like this:
$('[/^[a-z]{4,5}/}')
Could anyone please help me to get the right regexp?
You can't use regexp in selectors. You can pick some container and select its all elements and then filter them based on their class names. This probably won't be super fast, though.
I made a demo for you:
https://codepen.io/anon/pen/RZXdrL?editors=1010
html:
<div class="container">
<abc class="abc">abc</abc>
<abdef class="abdef">abdef</abdef>
<hdusf class="hdusf">hdusf</hdusf>
<ueff class="ueff">ueff</ueff>
<asdas class="asdas">asdas</asdas>
<asfg class="asfg">asfg</asfg>
<aasdasdbc class="aasdasdbc">aasdasdbc</aasdasdbc>
</div>
js (with jQuery):
const $elements = $('.container *').filter((index, element) => {
return (element.className.length === 5);
});
$elements.css('color', 'red');
The simplest way to do this would be to select those dynamic elements based on a fixed parent, for example:
$('#parent > *').each(function() {
// your logic here...
})
If the rules by which these tags are constructed are reliably as you state in the question, then you could select all elements then filter out those which are not of interest, for example :
var $elements = $('*').filter(function() {
return this.className.length === 5 && this.className.toUpperCase() === this.tagName.toUpperCase();
});
DEMO
Of course, you may want initially to select only the elements in some container(s). If so then replace '*' with a more specific selector :
var $elements = $('someSelector *').filter(function() {
return this.className.length === 5 && this.className.toUpperCase() === this.tagName.toUpperCase();
});
You can do this in vanilla JS
DEMO
Check the demo dev tools console
<body>
<things class="things">things</things>
<div class="stuff">this is not the DOM element you're looking for</div>
</body>
JS
// Grab the body children
var bodyChildren = document.getElementsByTagName("body")[0].children;
// Convert children to an array and filter out everything but the targets
var targets = [].filter.call(bodyChildren, function(el) {
var tagName = el.tagName.toLowerCase();
var classlistVal = el.classList.value.toLowerCase();
if (tagName === classlistVal) { return el; }
});
targets.forEach(function(el) {
// Do stuff
console.log(el)
})
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/
i'm learning javascript and i've tried something but i can't figure out how to make it work, here's my code so far:
HTML
<p>Busca tu auto:</p>
<input type="text" id="search"><span> </span><button>Submit</button>
<p class="hide h1" style="color:green">Your car is available.</p>
<p class="hide h2" style="color:red">Your car is not available.</p>
JS
$(document).ready(function(){
var cars = ['mercedes','nissan','ferrari','bmw','fiat','toyota','renault','peugeot','kia'];
$('.hide').hide();
$('button').click(function(){
if($('#search').val() == cars[x]){
$('.h1').show();
$('.h2').hide();
} else {
$('.h2').show();
$('.h1').hide();
};
});
});
What I want to do is that when you click the button check if the car is available (it's not real). For example, it you type "mazda" and click the button, h2 will show, but if you type "ferrari" and click the button, h1 will show.
I'm approaching to the solution with my code above or not?
NOTE: if you change the "x" in cars[x] for a number it works, but just with one car.
Array.prototype.indexOf
$(document).ready(function(){
var cars = ['mercedes','nissan','ferrari','bmw','fiat','toyota','renault','peugeot','kia'];
$('.hide').hide();
$('button').click(function(){
if(cars.indexOf($('#search').val()) !== -1){
$('.h1').show();
$('.h2').hide();
} else {
$('.h2').show();
$('.h1').hide();
};
});
});
http://jsfiddle.net/CWHDv/
You can search through arrays by using the Array.indexOf method:
if (cars.indexOf($('#search').val()) !== -1) {
//your code here
}
The Array.indexOf method will return -1 when no exact matches are found (this includes lowercase/uppercase differences), and otherwise it will return the index of the match in the array. That means that if the entered value is in your array, it will return something other than -1, so the if-statement will return true.
To make this case-insensitive, use the following:
if (cars.indexOf($('#search').val().toLowerCase()) !== -1) {
//available
} else {
//unavailable
}
that converts the input to lowercase first, and checks afterwards. For this to work, all values stored in the array would need to be in all lowercase letters too, like your example shows.
Since this question is also tagged jQuery:
From the jQuery docs:
jQuery.inArray( value, array [, fromIndex ] )
Which would be:
$.inArray(('#search').val(), cars) !== -1
This also has the advantage of working in IE8 and below, something that Array.prototype.indexOf does not.
<a href="javascript:void(0)" class="PrmryBtnMed"
id = "VERYLONGTEXT"
onclick="$(this).parents('form').submit(); return false;"><span>Dispatch to this address</span></a>
If I was to give instructions to a human, I would say:
look for a <span>Dispatch to this address</span> link; if it appears click it. (if there is more than one such link (for example there are two) just click the first one (or any of them)
I am using Greasekit, so I am looking to do this using JavaScript.
Thank you!
Updated: Now checks contents of element
var el = document.querySelector(".PrmryBtnMed"); //should only return first one
if (el && (el.textContent.trim() == 'Dispatch to this address')) {
el.click();
}
Have a look at the querySelector and textContent for more information
I also added a JsFiddle for you: http://jsfiddle.net/NrGVq/1/
A different approach is to search the whole page, in case it's not inside the matched element
var inPage = document.documentElement.innerHTML.indexOf('text to search') > 0,
el = document.querySelector(".PrmryBtnMed");
if (inPage && el) el.click();