I have an array of selectors like :
var arr = [".discuss .title .post", ".post .desc" , ".eventlist .event"];
I want to loop through this array and attach a click event on it.
for(var i in arr){
$(arr[i]).click(function(){
//here I need the selector i.e. arr[i] expression - for some css work
});
}
Is there a way by which I can get this selector expression inside the click callback function?
I went through this post which has similar problem : How do I get a jQuery selector's expression as text?
But as said there, I couldn't find any "selector" attribute of jQuery object. I tried this way:
for(var i in arr){
$(arr[i]).click(function(){
console.log(jQuery(this).attr('selector')); //This gives undefined
});
}
Any help?
The correct syntax is $('.something').selector. However, .selector only works when a selector string is explicitly supplied - but there is no selector in $(this).
One workaround is to save a copy of the selector in a function surrounding the click function:
for (var i = 0; i < arr.length; i++) { // (Don't use "for-in loop" for arrays)
(function (selector) { // 2. a copy is saved as the argument "selector"
$(selector).click(function () {
console.log(selector);
});
}) (arr[i]); // 1. Pass in the selector
}
Another option is to compare $(this) to each selector in your array, using .is():
$(arr.join(',')).click(function () { // a quick way to select all selectors
var selector;
for (var i = 0; i < arr.length; i++) {
if ($(this).is(arr[i])) {
selector = arr[i];
break;
}
}
console.log(selector);
});
You can at least get the class value of each selected element:
$(this).attr("class");
Doesn't this provide sufficient info for what you intend to do?
I don't seem to get any error, its as though there is no .click() event, example here
But if you split your array and attach a click to every item in your array it seems to work for me.
// Trouble is you will attach two click's to a class="post" item:
var arr = [".discuss .title .post", ".post .desc" , ".eventlist .event"];
for(var a in arr){
var ar = arr[a].split(' ');
for(var i in ar){
$(ar[i]).click(function(e){
e.preventDefault();
var href = $(this).attr('href');
var sele = $(this).attr('selector');
console.log(href);
console.log(sele);
alert("HREF: "+href+" - Selector: "+sele);
});
}
}
Take a look at it in action here along with a solution to stopping adding two clicks.
Related
I want to make a function that would detect a button on a web page and then click it. But I want it to click a specific item.
function imready()
{
var btn = document.getElementsByClassName('text-xxxs mb-02');
for (var i = 0; i < btn.length; i++)
{
if (btn[i].innerText.indexOf('AK-47') > -1)
{
console.log('runtime');
chrome.runtime.sendMessage({ type: 'dontrun', update: 1 }, function (response) {
});
btn[i].click();
pressok();
}
}
How do I make it so that the var "btn" should equal to document.getElementsbyClassName('x') and also a different className ('y')?
Quoting from https://stackoverflow.com/a/29366682/10450049
getElementsByClassName() returns an HTMLcollection object which is similar to an array but not really an array so you can't call
array methods using the returned value. One hack is to use Array's
prototype methods along with .call()/.apply() to pass the returned
object as the context.
var elems = document.getElementsByClassName("royal") ;
var collapsedElems = document.getElementsByClassName("collapsed");
var earray = Array.prototype.slice.call(elems, 0);
var concatenated = earray.concat.apply(earray, collapsedElems) ;
console.log(concatenated)
Demo Fiddle
As far as i understand your question, you can use document.querySelector('.classX.classY') to select the needed button with both classes.
That works for the case if you only need one button on the page selected, from your code i assume exactly that.
I'm trying to get the ids of any array of elements grabbed by the class name. I've tried several different ways, all of which I believe should work, but each way returns "undefined".
example of html:
<img id='1207_image-button' class='review-button' src="..." />
javascript:
var buttons = document.getElementsByClassName("review-button");
var button;
for (button in buttons) { alert(button.id); }
I've also tried this is the for loop:
alert($(this).attr('id'));
Each way returns "undefined", i'm not sure how to alert the actual id. If I put this in the loop:
alert(button);
It will loop through and output 0 through 5 (the number of elements) then output the ids so I know then are in the array I just don't know how to get to it.
for...in loop are used to iterate over objects. Not NodeList, which is not even an array. Use a good old for loop.
for(var i = 0; i < buttons.length; i++)
alert(buttons[i].id);
By using for ... in you're incorrectly iterating through the collection of buttons. Try this, instead:
var buttons = document.getElementsByClassName("review-button");
for (var i = 0, n = buttons.length; i < n; ++i) {
var id = buttons[i].id;
...
}
or alternately, in jQuery
$('.review-button').each(function() {
var id = this.id;
...
});
Considering you are using jquery use this;
$( ".review-button" ).each(function() {
alert($( this ).attr("id"));
});
the wrong part is the loop.
You have to do:
for (button in buttons) { alert(buttons[button].id); }
in this kind of loop, you assign the index of array, not the object in each cycle.
I got a problem to add a onclick event to object who can be many times in same page
I am trying to
var i;
for (i = 1; i<=10; i++) {
var tmpObj='lov_DgId_D_'+i;
var tmpObj2=tmpObj.getElementsByTagName('a')[0];
if (tmpObj2 != null) {
tmpObj2.onclick= DgIdOnClick;
}
}
But got a error TypeError:
Object lov_DgId_D_1 has no method 'getElementsByTagName' , but this is working
lov_DgId_D_2.getElementsByTagName('a')[0].onclick= DgIdOnClick;
This ibject lov_DgId_D_ can be from 1 like lov_DgId_D_1 or lov_DgId_D_99 u.t.c
What wil be the best solution to add onclick to all lov_DgId_D_* objects ?
As you use jquery, the simplest is
for (i = 1; i<=10; i++) {
$('#lov_DgId_D_'+ i+ ' a').click(DgIdOnClick);
}
If you want to bind your event handler to all a elements inside elements whose id starts with lov_DgId_D_, then it's as simple as
$('[id^="lov_DgId_D_"] a').click(DgIdOnClick);
The problem you have is a confusion between the id of an element and the actual element. Some code that should work for you is this one:
var i;
for (i = 1; i<=10; i++) {
var tmpObj=document.getElementById('lov_DgId_D_'+i); // <-- here
var tmpObj2=tmpObj.getElementsByTagName('a')[0];
if (tmpObj2 != null) {
tmpObj2.onclick= DgIdOnClick;
}
}
Slightly easier to read code:
for (var i=0; i<=10; i++) {
var anchor = document.querySelector('#lov_DgId_D_'+i + ' a');
if (anchor) anchor.onclick = DgIdOnClick;
}
A note: this code attaches a click event to the first anchor (a element) inside each element with the id lov_DgId_D_n, with n being 1->10. Your original code seems to want to do the same thing.
Another note: usually when you iterate over elements using their id's to identify them, you are better suited to add a class to those elements instead. It provides for more maintaintable code and probably easier to understand as well.
In this sort of function
function someFunction(divName)
{
document.getElementById(divName).style.someproperty = 'something'
document.getElementById(divName).style.someotherproperty = 'somethingelse'
}
called like this
onClick = "someFunction('someid')
Is there any way to have more than one divName that can be specified in the html?
e.g.
onClick = "someFunction('someid','someotherid')
The first getelementbyid being performed on 'someid' and the second on 'someotherid'
Preferably without jQuery
Edit:
I don't want to do the same thing to each of the two elements, I want to do something different to each individual element, but I want to be able to specify each element in the onClick ="..." instead of in the actual function, so that I don't have to write multiple functions for each combination of two target elements.
Sorry if that was unclear
The Answer (as it turns out, is really simple):
function someFunction(divName,divName2)
{
document.getElementById(divName).style.someproperty = 'something'
document.getElementById(divName2).style.someotherproperty = 'somethingelse'
}
html
onClick = "someFunction('someid','someotherid')"
When I tried it the first time, I wrote "someFunction('someid,someotherid')"
and when it didn't work I assumed that the solution wasn't as easy as divname1,divname2
Sorry, for making all of you run around writing fancy codes.
I assume you want to get an arbitrary number of arguments for a function. You can use the special arguments variable that comes in every called function. It's an array-like object that contains each argument passed into the function, in the order you placed them in the call.
You can do it like this:
function someFunction() {
for(var i = 0; i < arguments.length; i++){
document.getElementById(arguments[i]).style.someproperty = 'something'
}
}
However, classes might be better for this case, assuming you don't mind attaching classes to the target elements.
Give every your div a class name, for example "yourClass". Now you will have a function like this:
function someFunction(divClass) {
var eles = document.getElementsByClassName(divClass);
eles.style.someproperty = 'something';
eles.style.someproperty = 'something';
for(var i = 0; i< eles.length; i++){
// do some thing with each element
eles[i].style.someproperty = 'something';
}
}
Make the parameter an array and loop through it.
function someFunction(divIDs)
{
for (var i = 0; i < divs.length; i++)
{
document.getElementById(divIDs[i]).style.someProperty = 'something';
}
}
What you want to do is give all the elements you want to do something with a class which is the same for all of them, and an ID which is unique to all of them.
function someFunction(e) {
var action = false;
switch(e.target.id) {
case 'someid':
action = 'something';
break;
case 'someotherid':
action = 'somethingelse';
break;
case default:
break;
}
if(!action) return;
document.getElementById(e.target.id).style.someProperty = action;
}
You would then assign the onclick handler to the class:
onClick = "someFunction('theClassName')
If you have more than one element which you want to do the same thing to, instead of using an id, you would add a second class to those elements and just change the function to look for that class.
I am working in a Javascript library that brings in jQuery for one thing: an "ends with" selector. It looks like this:
$('[id$=foo]')
It will find the elements in which the id ends with "foo".
I am looking to do this without jQuery (straight JavaScript). How might you go about this? I'd also like it to be as efficient as reasonably possible.
Use querySelectorAll, not available in all browsers (like IE 5/6/7/8) though. It basically works like jQuery:
http://jsfiddle.net/BBaFa/2/
console.log(document.querySelectorAll("[id$=foo]"));
You will need to iterate over all elements on the page and then use string functions to test it. The only optimizations I can think of is changing the starting point - i.e. not document.body but some other element where you know your element will be a child of - or you could use document.getElementsByTagName() to get an element list if you know the tag name of the elements.
However, your task would be much easier if you could use some 3rd-party-javascript, e.g. Sizzle (4k minified, the same selector engine jQuery uses).
So, using everything that was said, I put together this code. Assuming my elements are all inputs, then the following code is probably the best I am going to get?
String.prototype.endsWith = function(suffix) {
return this.indexOf(suffix, this.length - suffix.length) !== -1;
};
function getInputsThatEndWith(text) {
var result = new Array();
var inputs = document.getElementsByTagName("input");
for(var i=0; i < inputs.length; i++) {
if(inputs[i].id.endsWith(text))
result.push(inputs[i]);
}
return result;
}
I put it on JsFiddle: http://jsfiddle.net/MF29n/1/
#ThiefMaster touched on how you can do the check, but here's the actual code:
function idEndsWith(str)
{
if (document.querySelectorAll)
{
return document.querySelectorAll('[id$="'+str+'"]');
}
else
{
var all,
elements = [],
i,
len,
regex;
all = document.getElementsByTagName('*');
len = all.length;
regex = new RegExp(str+'$');
for (i = 0; i < len; i++)
{
if (regex.test(all[i].id))
{
elements.push(all[i]);
}
}
return elements;
}
}
This can be enhanced in a number of ways. It currently iterates through the entire dom, but would be more efficient if it had a context:
function idEndsWith(str, context)
{
if (!context)
{
context = document;
}
...CODE... //replace all occurrences of "document" with "context"
}
There is no validation/escaping on the str variable in this function, the assumption is that it'll only receive a string of chars.
Suggested changes to your answer:
RegExp.quote = function(str) {
return str.replace(/([.?*+^$[\]\\(){}-])/g, "\\$1");
}; // from https://stackoverflow.com/questions/494035/#494122
String.prototype.endsWith = function(suffix) {
return !!this.match(new RegExp(RegExp.quote(suffix) + '$'));
};
function getInputsThatEndWith(text) {
var results = [],
inputs = document.getElementsByTagName("input"),
numInputs = inputs.length,
input;
for(var i=0; i < numInputs; i++) {
var input = inputs[i];
if(input.id.endsWith(text)) results.push(input);
}
return results;
}
http://jsfiddle.net/mattball/yJjDV/
Implementing String.endsWith using a regex instead of indexOf() is mostly a matter of preference, but I figured it was worth including for variety. If you aren't concerned about escaping special characters in the suffix, you can remove the RegExp.quote() bit, and just use
new RegExp(suffix + '$').
If you know the type of DOM elements you are targeting,
then get a list of references to them using getElementsByTagName , and then iterate over them.
You can use this optimization to fasten the iterations:
ignore the elements not having id.
target the nearest known parent of elements you want to seek, lets say your element is inside a div with id='myContainer', then you can get a restricted subset using
document.getElementById('myContainer').getElementsByTagName('*') , and then iterate over them.