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());
});
Related
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)
Hey guys need a bit of help here.
I'm trying to find all class names that start with the same naming convention in the DOM and put them all in to an array.
so for example.
<div class="userName_342">John</div>
<div class="userName_366">Doe</div>
<div class="userName_234">Bob</div>
<div class="userName_873">David</div>
I need help making the above code with a little bit of JavaScript to the array below.
var classArr = ["userName_342","userName_366","userName_234","userName_873"];
Any help on how to even get started would be greatly appreciated.
Thank you.
Assuming the relevant class is always the only class on those elements, you can do it with an "attribute starts with" selector combined with Array#map:
var list = document.querySelectorAll("div[class^=userName_]");
var classArr = Array.prototype.map.call(list, function(div) {
return div.className;
});
Matt Burland points out that that will return an array with duplicate entries if there are multiple elements with the same class. Two ways to address that:
Array#reduce, but this use of it isn't very efficient:
var list = document.querySelectorAll("div[class^=userName_]");
var classArr = Array.prototype.reduce.call(list, function(array, div) {
if (array.indexOf(div.className) === -1) {
array.push(div.className);
};
return array;
}, []);
...or using a temporary map:
var list = document.querySelectorAll("div[class^=userName_]");
var map = {};
Array.prototype.forEach.call(list, function(div) {
map[div.className] = true;
});
var classArr = Object.keys(map);
Array#map, Array#reduce, Array#forEach, and Object.keys are all ES5 features, but if you need to support older engines, they can all be shimmed.
querySelectorAll is available on all modern browsers, and IE8.
Here is an example of a function to find based on class name.
http://codepen.io/justindunham/pen/nhJsD
document['getElementsByRegex'] = function(pattern){
var arrElements = []; // to accumulate matching elements
var re = new RegExp(pattern); // the regex to match with
function findRecursively(aNode) { // recursive function to traverse DOM
//console.log(aNode);
if (!aNode)
return;
if (aNode.className !== undefined && aNode.className.search(re) != -1)
arrElements.push(aNode); // FOUND ONE!
for (var idx in aNode.childNodes) // search children...
findRecursively(aNode.childNodes[idx]);
};
findRecursively(document); // initiate recursive matching
return arrElements; // return matching elements
};
Based fully on this answer
Select div using wildcard ID
I currently the following jQuery collection / object:
[li.row-0, li.row-1, li.row-2, li-row-2, li.row-2, li.row-3]
Each class name is dynamically added to each element by a previous method. The only consistent part of the class name is row-. The number can be anywhere from 0 - ∞.
I want to create a new array or object of elements that are grouped by same dynamic class name:
[li.row-0]
[li.row-1]
[li.row-2, li.row-2, li.row-2, li.row-2]
[li.row-3]
The above is just a guess of the outcome, as I am not 100% sure how best to achieve this.
The aim is to be able to loop through .row-0, .row-1, .row-2, .row-3 and do something with the elements in each individual row.
I would do this :
var map = [].reduce.call(arr, function(map, v){
(map[v.className]||(map[v.className]=[])).push(v);
return map;
}, {});
var arr2 = [];
for (var className in map) arr2.push(map[className]);
The reduce builds a map having as keys the class names and with values the arrays of the elements having that class name.
I use [].reduce.call(arr, instead of arr.reduce( so that it works for standard arrays, jQuery collections, nodelists, etc.
Then the loop builds an array from that map. You might find the map more useful than the final array.
This shows you a general way of achieving this, though you're probably using elements rather than strings, but hopefully this will help
var tst = ['li.row-0','li.row-1','li.row-2','li.row-2','li.row-2','li.row-3'];
var grouped = [];
for(var i in tst)
{
var text = tst[i];
var num = text.replace('li.row-','');
if(!grouped[num]) grouped[num] = [];
grouped[num].push(text);
}
console.log(grouped);//[["li.row-0"], ["li.row-1"], ["li.row-2", "li.row-2", "li.row-2"], ["li.row-3"]]
Using elements:
var tst = [li.row-0,li.row-1,li.row-2,li.row-2,li.row-2,li.row-3];
var grouped = [];
for(var i in tst)
{
var text = tst[i].className;
var num = text.replace('row-','');
if(!grouped[num]) grouped[num] = [];
grouped[num].push(text);
}
console.log(grouped);//[["li.row-0"], ["li.row-1"], ["li.row-2", "li.row-2", "li.row-2"], ["li.row-3"]]
This method is more verbose and allows more complex grouping if need be (if other attributes come into play)
I would do something like the following:
var arr = ['li.row-0', 'li.row-1', 'li.row-2', 'li.row-2', 'li.row-2', 'li.row-3'];
var result = {};
$.each(arr, function (index, item) {
var ind = item.toString().split('row-')[1];
(result[ind] || (result[ind] = [])).push(item);
});
console.log(result);
What is the cleanest way to put the source attribute string of all images within a div into an array?
I was hoping this would work -
var imageSourceArray = $("#leDiv img").attr('src');
alert(imageSourceArray[3]); //not alerting the source, boo hoo.
Do I need to loop through $("#leDiv img") and add each src string to an array individually? Or is there a more elegant way to do this?
You can use jQuery's map function which is described as:
Pass each element in the current matched set through a function, producing a new jQuery object containing the return values.
For your example:
var mySources = $('#leDiv img').map(function() {
return $(this).attr('src');
}).get();
Edit: Far more elegant solution, there's obviously still some looping involved internally:
var img_sources = $('#leDiv img').map(function(){ return $(this).attr('src') });
You will in fact need to loop over the collection and add sources individually.
var img_sources = [];
$('#leDiv img').each(function(i,e){
img_sources.push($(e).attr('src'))
})
Some background: jQuery.fn.attr() maps to jQuery.access() internally, the key part of which looks like this:
function( elems, key, value, exec, fn, pass ) {
var length = elems.length;
// setter functions omitted here …
// Getting an attribute
return length ? fn( elems[0], key ) : undefined;
}
Note the elems[0] part – only the first item in the collection is fed to the subsequent callback function (jQuery.attr() in fact) responsible for extracting the information.
var imageSourceArray = [];
$('#leDiv img').each(function(){
var src = $(this).attr("src");
imageSourceArray.push(src);
});
alert(imageSourceArray[3]);
you already have the src in a collection when you fetch the the images. It may be more efficient to not store the src attributes in another array:
$('#leDiv img').each(function(i,e){
var dosomethingwith = $(e).attr('src');
})
or you could do:
var ImageCol = $('#leDiv img');
alert(ImageCol[3].attr('src'));
I'm splitting a string into an array, then I want to remove the white space around each element. I'm using jQuery. I'm able to do this successfully with 2 arrays but I know it's not correct. How do I loop thru an array and trim each element so the elements keep that change. Thanks for any tips. Here is my working code using two array. Please show me the correct way to do this.
var arVeh = vehicleText.split("|");
var cleanArry = new Array();
$.each(arVeh, function (idx, val) {
cleanArry.push($.trim(this));
});
Cheers,
~ck in San Diego
You don't even really need the idx or val parameters. This appears to work on jsFiddle:
var cleanVehicles = [];
$.each(vehicleText.split("|"), function(){
cleanVehicles.push($.trim(this));
});
EDIT: Now that I've seen what you're really after, try using map:
var cleanVehicles = $.map(vehicleText.split("|"), $.trim);
I'm going to suggest not using the overhead of jQuery for a simple for-loop...
var arVeh = vehicleText.split("|");
for (var i = 0, l = arVeh.length; i < l; ++i) {
arVeh[i] = $.trim(arVeh[i]);
});
Alternatively, get rid of the whitespace from the beginning, and avoid the need for another loop at all.
var arVeh = $.trim(vehicleText).split(/\s*\|\s*/);
Without 'creating' an array in the javascript code (an array will nevertheless be created in memory)
vehicles = $.map(vehicleText.split("|"), function(e,i) { return $.trim(e) });
var my_arr = [' cats', 'dogs ', ' what '];
$.each(my_arr, function (id, val) {
my_arr[id] = $.trim(val);
});
console.log(my_arr);
This will trim the value and set it to the indexed item.
You don't have to use JQuery. Here is your vanilla solution:
testArray.map(Function.prototype.call, String.prototype.trim);
Function.prototype.call calls trim() on each of the elements of the testArray. As simple as that!
Could you not just do this?
var arVeh = vehicleText.split("|");
$.each(arVeh, function (idx, val) {
arVeh[idx] = $.trim(this);
});
//a simple function
function trimArray(dirtyArray){
$.map(dirtyArray.split("|"), function(idx, val){
return $.trim(this);
});
}
trimArray(vehicleArray);
should do the trick
Or you could use some of the awesome power of javascript and use array.prototype. I'm still a little new at using the .prototype of any object... so this isnt guaranteed to work (but it certainly can be done).
Array.prototype.trim = function (){
$.map(dirtyArray.split("|"), function(idx, val){
return $.trim(this);
});
}
someArray.trim()
You need these two jQuery functions:
1.) iterate through array element with ability to edit items:
http://api.jquery.com/jquery.map/
2.) remove blank spaces from beginning and end of a string:
http://api.jquery.com/jQuery.trim/
Use them this way:
array = $.map(array, function(value) { return value.trim();});
Check this JSFiddle:
https://jsfiddle.net/L00eyL4x/49/