I want to write a simple javascript script to select from a large list of checkbox items on a website. Lets say I want to select the 3rd, 12th, and 25th checkbox. How would I do that? Right now it selects every item.
var script = document.createElement('script');
script.src = 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js';
script.type = 'text/javascript';
document.getElementsByTagName('head')[0].appendChild(script);
$("#detail input:checkbox").click();
I would use filter() and prop()
var indexesToCheck = [2,11,24];
$("#detail input:checkbox").filter(function(index){
return $.inArray( index, indexesToCheck ) > -1;
/* OR something like*/
return $(this).hasClass('someClass');
}).prop('checked',true);
Since it's not clear how you intend to determine which ones get checked I used a simple array. You could aslo check classes or any other element attributes inside filter using this which would be the instance of each element
References:
filter() docs
prop() docs
I will provide a solution in javascript and equivalent jQuery. I added a last solution (my favourite), which would generic, creating a custom pseudo selector.
For javascript, I chose all the inputs and verify their type. Incrementing a counter when the type is checkbox. Then I compare with an array of the indexes I want to select and I push the element to the final array with all my elements (mySelection):
var mySelection = [];
var checkboxIndexes = [3,12,25];
var checkCounter = 0;
var allInputs = document.getElementsByTagName("input");
for(var i=0;i<allInputs.length;i++) {
if (allInputs[i].type == 'checkbox') {
if(checkboxIndexes.indexOf(checkCounter) > -1;)
mySelection.push(allInputs[i]);
checkCounter++;
}
};
For the jQuery you could use:
$('#detail input:checkbox:eq(index)');
But I did an equivalent to the javascript one using filter. I personally like more this solution since you can put all the index to be selected in one array:
var checkboxIndexes = [3, 12, 25];
var mySelection = $("#detail input:checkbox").filter(function(index) {
return checkboxIndexes.indexOf(index) > -1;
});
The last solution would be a generic solution which will allow to create a custom pseudo selector that I called "multieq". The goal is to use "multieq" as a filter directly from the selector in this way:
var mySelection = $("input:checkbox:multieq(3, 12, 25)");
And this is the code I used in order to create that pseudo selector:
$.expr[':'].multieq = $.expr.createPseudo ?
$.expr.createPseudo(function(match) {
var checkboxIndexes=match.split(',');
for(var i=0; i<checkboxIndexes.length;i++) checkboxIndexes[i] = parseInt(checkboxIndexes[i], 10);
var index=-1;
return function( elem, doc, isXML ) {
index++;
return checkboxIndexes.indexOf(index) > -1;
};
}) :
function( elem, index, match ) {
var checkboxIndexes=match[3].split(',');
for(var i=0; i<checkboxIndexes.length;i++) checkboxIndexes[i] = parseInt(checkboxIndexes[i], 10);
return checkboxIndexes.indexOf(index) > -1;
};
//Now we can use this:
var mySelection = $("input:checkbox:multieq(3, 12, 25)");
Since 1.8+ $.expr breaks for certain cases and it is not including the param index, it is recommended to use createPseudo(), that is why there is a fallback function for jQuery version under 1.8. createPseudo, does not include index neither but allow us to create the index (as a counter).
I hope it helps!
<input type="checkbox" name="multi_selection"/>
var idArr = [];
$.each($("input[name='multi_selection']:checked"), function(){
idArr.push($(this).val());
});
Now idArr is the array of the selected checkboxes... alert(idArr)
Related
Original code:
item_boxes = $(".item-box")
$.each(item_boxes, function() {
var id = $(this).data("id")
$(this).find(".price").text(price_list[id])
})
JS code:
item_boxes = $(".item-box")
for(var i=0; i<item_boxes.length; i++) {
var id = item_boxes[i].getAttribute("data-id")
item_boxes[i].find... .text
// above line doesn't work, because it's jQuery
// item_boxes[i].querySelector(".price"), finds the child element, but then I can't figure out how to add the price info
// item_boxes[i].querySelector(".price").innerHTML(price_list[id]) throws a nomethod error on innerHTML
}
ooops sorry tanks for the responses, but I guess the quesiton wasn't clear, I'm moving TO the latter code (JS). I'd like the latter code to duplicate the same functionailty as former, but currently it does not. item_boxes[i].find throws a no method error on .find, so then I did querySelector, which finds the object, but there's no .text method to change the text.
Basically what the code is doing is looking at all the item_boxes, and on each of them, changing the text of the child price element.
Use the eq(id) method to fetch a jQuery object.
Proceed with data() as well.
var item_boxes = $(".item-box"),
i = 0,
el, id;
for(; i < item_boxes.length; i++) {
el = item_boxes.eq(i);
id = el.data("id");
el.find(".price").text(price_list[id]);
}
Notice with the for loop, all variables are extracted to it's function scope, which is more imaginary in this example. Use $.each(items, function(i, item){/*vars*/}) if you want to keep variables together.
Without jQuery:
var item_boxes = document.querySelectorAll(".item-box"),
i = 0,
el, id;
for(; i < item_boxes.length; i++) {
el = item_boxes[i];
id = el.dataset.id;
//el.querySelectorAll
el.querySelector(".price").innerHTML = price_list[id];
}
Following JQuery docs sample :
$.each([ 52, 97 ], function( index, value ) {
alert( index + ": " + value );
});
You can do much better without jQuery by using modern features, and a transpiler if needed.
for (const box of document.querySelectorAll(".item-box")) {
box.querySelector(".price").textContent = price_list[box.dataset.id];
}
The longest part is the function names, so you can shorten them.
function query(root, sel) {
return root.querySelector(sel);
}
function queryAll(root, sel) {
return root.querySelectorAll(sel)
}
So now it looks like this:
for (const box of queryAll(document, ".item-box")) {
query(box, ".price").textContent = price_list[box.dataset.id];
}
Make the function names as short as you like.
$.each takes two arguments. The first one is what it calls the index, the second one is what it calls the element.
As for "acting" on the data, it depends on whether you're talking about manipulating what you're iterating over or whether you're just manipulating the values that the function is returning.
To change what you're iterating over, use the index to select each respective item in what you're iterating over:
var list = [27, 43, 19];
$.each(list, function(i, element) {
list[i] += 7
});
To change the values being returned, just do whatever. They're variables.
var list = [27, 43, 19];
$.each(list, function(i, element) {
i += 3
element += 91
});
You could use ES6 Map method
It'd be something like
item_boxes.map( (item_box,index) => {
var id = item_box.getAttribute("data-id")
item_box.find... .text //if you actually need to do something with the index
})
I'm trying to create an array in Javascript with a size that is equivalent to the number of times a certain class is found in the DOM, and then iterate through it to grab the text from an input field present in that class. I can easily do this like so:
var count = 0;
$('.className').each(function() {
count++;
});
var classes = new Array(count);
count = 0;
$('.className input[type=text]').each(function() {
classes[count++] = $(this).val();
});
This looks like a lot of code for what seems to be a relatively simple task. Is there a more efficient or less lengthy way of doing this?
Thanks
It looks like you want this :
var classes = $('.className input[type=text]').map(function(){
return this.value
}).get();
But it's a guess : it's not clear why you start by counting all elements of the class and then iterate on the inputs.
You can construct an array of elements directly from your selector via the makeArray function, then transform the result using a map.
var classes = $.makeArray($('.className input[type=text]')).map(function() {
return $(this).val();
});
Use jQuery's map function, then get if you need a pure array:
var values = $('.className input[type=text]').map(function() {
return $(this).val();
}).get();
each passes the index, so you don't need to do it yourself:
var classes = [];
$('.className input[type=text]').each(function(index, value) {
classes[index] = $(this).val();
});
Arrays are dynamic and therefore don't need to be initialized. Create a new array, loop through the inputs and push the values to the new array:
var classes = [];
$('.className input[type=text]').each(function(idx, elem) {
classes.push($(elem).val());
});
I have a div with the following classes:
form-group val-presence-text val-type-pos-int val-length-10 has-success has-feedback
I want to get the 10 from the val-length-10 class name. I've tried various methods, but none seem to work for a dynamic multi-class attribute such as this. In addition, the 10 could be any positive integer and the class could be located anywhere within the group of classes.
Any ideas?
You can use this:
var val_length = $('div').attr("class").match(/val-length-(\d+)/)[1];
One possible solution:
var n = (this.className.match(/val-length-(\d+)/) || []).pop();
Or in the context:
$('[class*="val-length-"]').each(function() {
var n = (this.className.match(/val-length-(\d+)/) || []).pop();
console.log(n);
});
Assuming that the it is 'val-length' that never changes and just the integer on the end of it, you should be able to do this:
//get an array of classes on a specific element
var classList =$('#elementId').attr('class').split(/\s+/);
//loop through them all
$.each( classList, function(index, item){
//check if any of those classes begin with val-length-
if (item.indexOf('val-length' === 0) {
console.log(item.substring(11))
}
});
Try this...
$("div[class*=val-length-]").each(function() {
var s = this.className;
var length = 0;
$(s.split(" ")).each(function() {
if (this.search("val-length-") === 0) {
length = this.substr(11);
}
});
console.log(length);
});
It will find the relevant div and pull the value for you.
I would like to get all the elements/nodes in an HTML page which contain attributes that start with something (again, the attribute names start with something, not their values!). For example, TinyMCE has a tendency of adding custom attributes to the elements it saves, like "mce_style", "mce_href", "mce_bogus", etc. I would like to have something like the CSS3 selector for attribute values, [attr^="mce_"], but not for the values, the attribute names.
Of course, I can iterate through all DOM nodes and their attributes and check them one by one, but I was wondering whether there is a more efficient way.
Please don't give me TinyMCE-specific answers, I'm pretty sure there's a flag which would prevent TinyMCE for saving these attributes, but the question is generic.
here's a simple demo to find all elements that contain an attribute starting with mce_. might need some refinements.
function getMCE() {
var el, attr, i, j, arr = [],
reg = new RegExp('^mce_', 'i'), //case insensitive mce_ pattern
els = document.body.getElementsByTagName('*'); //get all tags in body
for (i = 0; i < els.length; i++) { //loop through all tags
el = els[i] //our current element
attr = el.attributes; //its attributes
dance: for (j = 0; j < attr.length; j++) { //loop through all attributes
if (reg.test(attr[j].name)) { //if an attribute starts with mce_
arr.push(el); //push to collection
break dance; //break this loop
}
}
}
return arr;
}
console.log(getMCE())
Try this:
FUNCTIONS
//custom selector expression
$.extend($.expr[':'],{
attr:function(o,i,m){
var attrs=$.getAttrAll(o),re=m[3],found=false;
$.each(attrs,function(k,v){
if(new RegExp(re).test(v)) { return found=true;}
});
return found;
}
});
// get all atrributes of an element
$.getAttrAll=function(el){
var rect = [];
for (var i=0, attrs=el.attributes, len=attrs.length; i<len; i++){
rect.push(attrs.item(i).nodeName);
}
return rect;
};
`
USAGE
// calling custom selector expression :attr(regexp)
$(function(){
$('body').find(':attr("^mce_")').css({background:'yellow'});
});
HTML
<body>
<p mce_style="height:50px" id="x" data-hello="hello">selected</p>
<div not_mce_bogus="abc">not_mce_bogus</div>
<div mce_href="http://rahenrangan.com">selected</div>
<p>othrs</p>
</body>
One option, if you don't mind temporarily altering your DOM, is to extract your HTML into a string and search for the attributes via RegExp. When you find the attributes, you could append a "needle" in the DOM so that you can use jQuery to select the elements.
Here is a working concept (run with console open):
http://jsfiddle.net/skylar/N43Bm/
Code:
$.fn.extend({
findAttributes: function(attribute) {
var attributeFinder = new RegExp(attribute + '(.+)="', "gi");
var elementHTML = this.html().replace(attributeFinder, "data-needle='pin' "+attribute+"$1=\"");
this.html(elementHTML);
return this.find("[data-needle=pin]").removeAttr('data-needle');
}
});
console.log($("body").findAttributes('mce_'));
Note: my regexp is not great. You'll have to take better care than I have in this example.
Try this: (I tried putting * instead of a tag but it colored all the elements including those who do not have mce_style attribute as well)
a[mce_style] { color : red; }
Demo : http://jsfiddle.net/Tcdmb/
More info : https://developer.mozilla.org/en/CSS/Attribute_selectors
I would like to change the class for all the fields in a specific fieldset.
Is there a way to loop through the fields in a fieldset?
You can use getElementsByTagName.
var fieldset= document.getElementById('something');
var fieldtags= ['input', 'textarea', 'select', 'button'];
for (var tagi= fieldtags.length; tagi-->0) {
var fields= fieldset.getElementsByTagName(fieldtags[tagi]);
for (var fieldi= fields.length; fieldi-->0;) {
fields[fieldi].className= 'hello';
}
}
(If you only care about input fields, you could lose the outer tag loop.)
If you needed them in document order (rather than grouped by tag) you'd have to walk over the elements manually, which will be a pain and a bit slow. You could use fieldset.querySelectorAll('input, textarea, select, button'), but not all browsers support that yet. (In particular, IE6-7 predate it.)
Using jQuery (yay!):
$('#fieldset-id :input').each(function(index,element) {
//element is the specific field:
$(element).doSomething();
});
Note the solution below is for NON-JQUERY Implementations.
Implement a getElementsByClassName Method like this:
After you implement the code below you can then use document.getElementsByClassName("elementsInFieldSetClass") it will return an array of the elements with that class.
function initializeGetElementsByClassName ()
{
if (document.getElementsByClassName == undefined) {
document.getElementsByClassName = function(className)
{
var hasClassName = new RegExp("(?:^|\\s)" + className + "(?:$|\\s)");
var allElements = document.getElementsByTagName("*");
var results = [];
var element;
for (var i = 0; (element = allElements[i]) != null; i++) {
var elementClass = element.className;
if (elementClass && elementClass.indexOf(className) != -1 && hasClassName.test(elementClass))
results.push(element);
}
return results;
}
}
}
window.onload = function () {
initializeGetElementsByClassName();
};
Another jQuery solution here.
If you are simply adding a class(es) to the elements, it's this simple:
$('fieldset :input').addClass('newClass');
.addClass() (like many other jQuery functions) will work on all of the elements that match the selector.
Example: http://jsfiddle.net/HANSG/8/
Permanently? Find & replace in your editor of choice.
When the user clicks something? jQuery way:
$('fieldset <selector>').each(function() {
$(this).removeClass('old').addClass('new');
});