Diffrence between HTML collection & an Array in Javascript - javascript

Following code produces nothing but an error. I wish to retrieve REL attribute values of each of the DIVs. No idea, why I can'y do it.
Error I see in console: Uncaught TypeError: Object # has no method 'getAttribute'
<div class="boxes">
<div rel="first" class="box">Box 1</div>
<div rel="second" class="box">Box 2</div>
<div rel="third" class="box">Box 3</div>
</div>
<script>
$(function(){
var i = 0;
var allDivs = document.getElementsByClassName('box');
var arr = [];
arr.push(allDivs);
setInterval(function(){
console.log(arr[i].getAttribute('rel'));
i++;
}, 1000);
});
</script>

you're pushing an array (NodeList to be exact) into an array and trying to get the attribute from the NodeList object instead of the individual elements. Try this:
<div class="boxes">
<div rel="first" class="box">Box 1</div>
<div rel="second" class="box">Box 2</div>
<div rel="third" class="box">Box 3</div>
</div>
<script>
$(function(){
var i = 0;
var allDivs = document.getElementsByClassName('box');
var arr = [];
arr.push(allDivs);
setInterval(function(){
console.log(arr[0][i].getAttribute('rel'));
i++;
}, 1000);
});
</script>
By pushing the NodeList into the other array, you are essentially creating this:
var arr = [[<div element 1>, <div element 2>, <div element 3>]];
What you are probably wanting to do is to change your push line to:
arr.push.apply(arr, allDivs);
That will append all the individual elements inside the allDivs collection onto arr. Then you can access arr like you expected before: arr[i].getAttribute('rel') (arr's contents will be [<div element 1>, <div element 2>, <div element 3>];)

Replace the script with this:
$(function(){
var i = 0;
var allDivs = document.getElementsByClassName('box');
//allDivs itself is an array and there is no need to push the result to an array.
setInterval(function(){
console.log(allDivs[i].getAttribute('rel'));
i++;
}, 1000);
});

Related

Cant get CSS property from child?

I have this HTML code here :
<div id="ctr" class="faden-slider-container">
<div class="conteneur-image" ></div>
<div class="conteneur-image" ></div>
<div class="conteneur-image" ></div>
</div>
And I am trying to get the CSS property of the second div which class' name is conteneur-image but I get nothing :
app.controller("slideCtrl",function ($scope) {
alert("hello")
var tab = new Array();
var elements = new Array();
for(var i = 0; i<3 ; i++){
elements[i] = document.getElementById("ctr").children[i]
}
var style = window.getComputedStyle(elements[1])
var message = style.getPropertyCSSValue("background").cssText()
alert("CSS Value is : "+message)
})
Couple of issues there.
getPropertyCSSValue is obsolete and may not work in browsers anymore
id is a selector, not a valid css property
Use getPropertyValue instead,
var message = style.getPropertyCSSValue("background");
Demo
var style = window.getComputedStyle(document.getElementById("ctr").children[1])
var message = style.getPropertyValue("background");
console.log("CSS Value is : " + message)
<div id="ctr" class="faden-slider-container">
<div class="conteneur-image"></div>
<div class="conteneur-image"></div>
<div class="conteneur-image"></div>
</div>
Using jquery,you can get your 2nd HTML element this way:
var element = $("#ctr").children().eq(1);
Then if you want to make some transformation, like applying style:
element.css("background-color", "blue")
Here is a snippet:
var element = $("#ctr").children().eq(1);
element.css("background-color", "blue")
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="ctr" class="faden-slider-container">
<div class="conteneur-image" >one</div>
<div class="conteneur-image" >second</div>
<div class="conteneur-image" >third</div>
</div>

Giving a unique text to each element

So... I have four divs on a page. All four of them belong to the class foobar. What I wanna do here is give each of them a value from a certain Array in JavaScript. Do note I am using jQuery 3.2.1.
My JavaScript:
var $elements = jQuery.makeArray($(".foobar"));
[1,2,3,4].forEach(function (x) {
$elements.forEach(function (y) {
y.text(x.toString());
});
});
My HTML:
<div class="foobar"></div>
<div class="foobar"></div>
<div class="foobar"></div>
<div class="foobar"></div>
And as always, it does not work. Basically what I wanna do here is give each Number in that Array as the text() for each div.
You are setting the same text to every element inside inner loop. Try this
var $elements = $(".foobar");
[1,2,3,4].forEach(function (x, i) {
$($elements[i]).text(x)
});
Or use .text(func)
var texts = [1,2,3,4];
var $elements = $(".foobar").text(function(i) {
return texts[i];
})
Check this fiddle. https://jsfiddle.net/bj3s92gr/
Bassicaly you have to bucle the divs with class foobar, and assing the position of the array in the html.
var $elements = $(".foobar");
$arr = [1,2,3,4];
$elements.each(function(e){
$(this).html($arr[e]);
});
Create an array of numbers, traverse thru all the .foobar elements, and assign a value from the array.
var $elements = jQuery.makeArray($(".foobar"));
var numbers = [1, 2, 3, 4];
var count = 0;
$(".foobar").each(function() {
$(this).text(numbers[count]);
count++;
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
My HTML:
<div class="foobar"></div>
<div class="foobar"></div>
<div class="foobar"></div>
<div class="foobar"></div>

How to iterate through HTML entities with javascript

I have the following HTML [below]. I am trying to iterate through all DOM with class="gmvcRow", and grab the text in all of the "gmvcCell" for each 'gmvcRow'. I would like to place all the text in an array(['firstname', 'lastname', 'dob', 'city']). And i would like to place this array into another array that holds "arrays of gmvcRow". My attempt is below but i am still not successful. I understand that the text in 'gmvcCell' is in itself another label node.
<div class="gmvcRow">
<div class="gmvcCell">firtname</div>
<div class="gmvcCell">lastname</div>
<div class="gmvcCell">dob</div>
<div class="gmvcCell">city</div>
</div>
<div class="gmvcRow"></div>
<div class="gmvcRow"></div>
<div class="gmvcRow"></div>
<div class="gmvcRow"></div>
<div class="gmvcRow"></div>
my code:
var gmvcRowArray = document.getElementsByClassName('gmvcRow');
console.log('number of records: ' + gmvcRowArray.length);
// Master array
var masterArray = [];
// Iterate through array
for(var i=0; i<gmvcRowArray.length; i++){
// Iterate through all childNodes
var rowArray = [];
for(var c=0; c<gmvcRowArray[i].childNodes.length; c++){
c = c + 1; // skip non text node
console.log('c: '+c);
if(gmvcRowArray[i].childNodes[c] != null){
var value = gmvcRowArray[i].childNodes[c].innerHTML;
rowArray.push(value);
//console.log('rowArray.length: '+rowArray.length);
console.log('value: '+value);
}
c = c - 1;
}
// Add row to master array
masterArray.push(rowArray);
console.log('masterArray.lengh: '+masterArray.length);
}
Using childNodes makes it harder than needed, since it also selects text nodes.
Instead use some of the ES6 features, which lead to concise code:
var arr = Array.from(document.querySelectorAll('.gmvcRow'), row =>
Array.from(row.querySelectorAll('.gmvcCell'), cell => cell.textContent)
);
console.log(arr);
<div class="gmvcRow">
<div class="gmvcCell">firstname</div>
<div class="gmvcCell">lastname</div>
<div class="gmvcCell">dob</div>
<div class="gmvcCell">city</div>
</div>
<div class="gmvcRow">
<div class="gmvcCell">Helene</div>
<div class="gmvcCell">Johnson</div>
<div class="gmvcCell">11/11/1995</div>
<div class="gmvcCell">Paris</div>
</div>
Quick sample for 1-level nesting
var rows = Array.from(document.getElementById('container').querySelectorAll('.gmvcRow'));
const result = rows.map(row => {
return Array
.from(row.querySelectorAll('.gmvcCell'))
.map(cell => cell.innerText);
});
console.log(result);
https://jsfiddle.net/snba2qsf/
After all you can filter result to exclude empty arrays
In your Script: Just check the value before adding to row array whether Is not null and not undefined.
if(value != null || value != undefined)
{
rowArray.push(value.trim());
}
Here is my answer using querySelectorAll
var gmvcRowArray = [];
document.querySelectorAll('.gmvcRow').forEach((el, idxRow) =>{
var gmvcCellArray = [];
el.querySelectorAll('.gmvcCell')
.forEach((el) =>{
gmvcCellArray.push(el.innerText);
});
gmvcRowArray.push(gmvcCellArray)
})
console.log(gmvcRowArray)
<div class="gmvcRow">
<div class="gmvcCell">Name1</div>
<div class="gmvcCell">lastname1</div>
<div class="gmvcCell">dob1</div>
<div class="gmvcCell">city1</div>
</div>
<div class="gmvcRow">
<div class="gmvcCell">Name2</div>
<div class="gmvcCell">lastname2</div>
<div class="gmvcCell">dob2</div>
<div class="gmvcCell">city2</div>
</div>
<div class="gmvcRow"></div>
<div class="gmvcRow"></div>
<div class="gmvcRow"></div>
<div class="gmvcRow"></div>

Simplify function for removing duplicate array

I want to find div element that contain custom attribute mod than append that div to list item. But first I have to remove divs that contain duplicate mod value. Here's what I have done
<div class="list"></div>
<div class="container">
<div mod="dog"></div>
<div mod="man"></div>
<div mod="woman"></div>
<div mod="dog"></div>
<div mod="bird"></div>
<div mod="insects"></div>
<div mod="dog"></div>
</div>
this is my script
modArr($('.container').find('[mod]'))
function modArr(el){
var filterArray = [] // store mod
, modNames = [] // store mod value
, arrIndex = [] // store non duplicate index
, li = [] // store
modArray = el
// store mod value
for(var i=0; i < modArray.length; i++){
modNames.push($(modArray[i]).attr('mod')) // get mod value from div
}
// search for non duplicate mod value and get the index of none duplicate mod
for(var i=0; i < modArray.length; i++){
if(filterArray.indexOf(modNames[i]) === -1){
filterArray.push(modNames[i])
arrIndex.push(i) // push non duplicate index value
}
}
filterArray = [] // reset filterArray
// push module from modArray to filterArray using index in arrIndex
for(var i=0; i < arrIndex.length; i++){
filterArray.push(modArray[arrIndex[i]])
}
// push to li array
$.each(filterArray,function(i,el){
li[i] = '<li>'+ el.outerHTML +'</li>'
})
$('<ul></ul>')
.append(li.join(''))
.appendTo('.list')
}
What you can see is that I've used to many loops, is there any simple way to do this. Thanks!
We can use an object as a map for checking duplicates, see comments (I've added text to the mod divs so we can see them):
modArr($('.container').find('[mod]'));
function modArr(elements) {
// A place to remember the mods we've seen
var knownMods = Object.create(null);
// Create the list
var ul = $("<ul></ul>");
// Loop the divs
elements.each(function() {
// Get this mod value
var mod = this.getAttribute("mod");
// Already have one?
if (!knownMods[mod]) {
// No, add it
knownMods[mod] = true;
ul.append($("<li></li>").append(this.cloneNode(true)));
}
});
// Put the list in the .list element
ul.appendTo(".list");
}
<div class="list"></div>
<div class="container">
<div mod="dog">dog</div>
<div mod="man">man</div>
<div mod="woman">woman</div>
<div mod="dog">dog</div>
<div mod="bird">bird</div>
<div mod="insects">insects</div>
<div mod="dog">dog</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
We can also just use the DOM to check for duplicates, but it's a bit slower (not that it matters for the number of elements here):
modArr($('.container').find('[mod]'));
function modArr(elements) {
// Create the list
var ul = $("<ul></ul>");
// Loop the divs
elements.each(function() {
// Get this mod value
var mod = this.getAttribute("mod");
// Already have one?
if (ul.find('div[mod="' + mod + '"]').length == 0) {
// No, add it
ul.append($("<li></li>").append(this.cloneNode(true)));
}
});
// Put the list in the .list element
ul.appendTo(".list");
}
<div class="list"></div>
<div class="container">
<div mod="dog">dog</div>
<div mod="man">man</div>
<div mod="woman">woman</div>
<div mod="dog">dog</div>
<div mod="bird">bird</div>
<div mod="insects">insects</div>
<div mod="dog">dog</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Note: I used this.cloneNode(true) rather than outerHTML because there's no need to take a roundtrip through markup. If you want more jQuery there, it's $(this).clone(); ;-) Similarly, if you don't like this.getAttribute("mod"), there's $(this).attr("mod").
I'd be remiss if I didn't point out that mod is an invalid attribute name for div elements. You can use any name you want starting with data-, though, so perhaps use <div data-mod="dog"> instead.
Try this, only adds if an element with mod is not already in list:
$('.list').append('<ul>');
$('.container [mod]').each(function(index, el) {
if($('.list [mod=' + $(el).attr('mod') + ']').length === 0) {
$('.list ul').append($('<li>' + el.outerHTML + '</li>'));
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="list"></div>
<div class="container">
<div mod="dog">Dog1</div>
<div mod="man">Man1</div>
<div mod="woman">Woman1</div>
<div mod="dog">Dog2</div>
<div mod="bird">Bird1</div>
<div mod="insects">Insect1</div>
<div mod="dog">Dog3</div>
</div>

jQuery: how to loop through elements with data attribute

I have several divs that looks like this:
<div class='popupDiv' data-layergroup='layer1'>divcontent 1</div>
<div class='popupDiv' data-layergroup='layer1'>divcontent 2</div>
<div class='popupDiv' data-layergroup='layer2'>divcontent 3</div>
<div class='popupDiv' data-layergroup='layer2'>divcontent 4</div>
I'm a bit stumped as to how to loop through all popupDiv divs, and then loop through each layergroup separately. I want to end with a single array for each layergroup. I'd need something like:
var mainArray = [];
$('.popupDiv').each(function(){
var tempArray = [];
$([unique layer value]).each(function(){
// Put div values from layergroup in tempArray
});
mainArray.push(tempArray);
});
return mainArray;
But I don't know the syntax I'm looking for. What do I do?
<div class='popupDiv' data-layer='layer1'></div>
<div class='popupDiv' data-layer='layer1'></div>
<div class='popupDiv' data-layer='layer2'></div>
<div class='popupDiv' data-layer='layer2'></div>
Loop through the elements
$('.popupDiv[data-layer]').each(function(){
});
to loop through each group seperately, you can use below logic
//create an array to store processed data-layer type
var dataArray = new Array();
$('.popupDiv').each(function(){
var dataLayer = $(this).data('layer');
//check if data-layer already processed
if(!dataArray.indexOf(dataLayer))
{
//update data array
dataArray.push(dataLayer);
$('.popupDiv[data-layer="'+ dataLayer +'"]').each(function(){
//do your stuff here
});
}
});
You can loop through each of the div having attribute 'data-layer' as follows:
$('.popupDiv').each(function(i) {
if ($(this).attr('data-layer') == 'layer' + i + 1) {
$(this).each(function() {
alert($(this).attr('data-layer'));
//change this to whatever you want
});
}
});
So this will check for 'layer1', 'layer2' and so on.
You do not need two each loops here. You can use Has Attribute Selector. you are also having duplicate IDs for divs. IDs should be unique, use class name instead:
$('[data-layergroup]').each(function(){
// Do stuff with each div
console.log($(this).data('layergroup'));//current data layer value
});
For iterating over the values(FYI-BAD APPROACH):
$.each($("[data-layergroup]").map(function() { return $(this).data('layergroup');}).get(), function(index, item) {
// item
});
use class instead of id:
<div class='popupDiv' data-layer='layer1'></div>
<div class='popupDiv' data-layer='layer1'></div>
<div class='popupDiv' data-layer='layer2'></div>
<div class='popupDiv' data-layer='layer2'></div>
Then you can loop each layer seperatly:
for (var i = 1; i <= 2; i++) {
$(".popupDiv[data-layer|='layer"+i+"']").each(function(){
// do stuff with layer i
});
}

Categories

Resources