How to iterate through HTML entities with javascript - 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>

Related

Find index of array elements on div mouseenter. Which is the best of these 3 methods?

I have an array of elements with their ids, stamped inside my html file; I need to find the index on mouseover based on the same id.
I have tried and found 3 good codes/solutions like this:
HTML
<div class="element" data-id="3"> </div>
<div class="element" data-id="2"> </div>
<div class="element" data-id="1"> </div>
<div class="element" data-id="4"> </div>
myArray = [{ _id:1}, {_id:2}, { _id:3}, { _id:4}];
$('.element').on('mouseenter', function (){
findIndex($(this).data('id'));
})
These are my 3 solutions:
forEach
function findIndex (boxId){
var boxIndex;
myArray.forEach(function(el, index){
if (boxId === el._id) {
boxIndex = index + 1
}
})
return boxIndex;
}
Map + indexOf
function findIndex (boxId){
var index = myArray.map(function(el) {return el._id; }).indexOf(boxId);
return index;
}
Map + filter
function findIndex (boxId){
var index = myArray.map((el, i) => el._id === boxId ? i : '').filter(String);
return index;
}
Which is the best for you? In terms of performance or good code.
I like the first and the second.

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>

Displaying results, in different div's from a JavaScript loop

var parseResponse = function() {
var data = JSON.parse(this.response);
console.log (data);
var head = "Cheapest Flight to " + document.getElementById('search_term1').value;
var bodystuff = document.createElement('h4');
bodystuff.innerHTML = head;
document.getElementById('right1').appendChild(bodystuff);
for (var i=0; i<data.results.length; i++) {
try {
var printDeparture = "Depart: " +
data.results[i].itineraries[i].outbound.flights[i].departs_at;
var bodystuff = document.createElement('p');
bodystuff.innerHTML = printDeparture;
document.getElementById('right1').appendChild(bodystuff);
console.log(printDeparture);
} catch (err) {
console.log(data.results[i]);
}
}
}
I am trying to get each result printed out in a separate div (currently, I have 3 results back) but can only print out the first of the three, I have tried to increase [i] in each of the results, and changed the divs from "right1" to "left1" but nothing happens. any help?
Here is my HTML code;
<div class="wrap">
<div class="left">
<img src="Assets/China.png" class="pics">
</div>
<div class="right" id="right1">
</div>
</div>
<div class="wrap">
<div class="left" id="left1">
</div>
<div class="right" >
<img src="Assets/hotel.jpg" class="pics">
</div>
</div>
and here is the result I get back from the API:
Object
results
:
Array[3]
0
:
Object
1
:
Object
2
:
Object
(hope it makes sense)

Looping through div rows and collecting the id of the row and column values

I have divs acting like a table and I want to loop through each div row in jquery and collect the column values (and also the row id)
How can I do it? code is in this jsffiddle
https://jsfiddle.net/DTcHh/24064/
HTML
<div id="tasksTableDiv">
<div class="row taskRow" id="1">
<div id="description_1"
class="col-sm-2 taskDescriptionCol">Description 1
</div>
<div id="colour_1"
class="col-sm-2 taskColourCol">Blue
</div>
</div>
<div class="row taskRow" id="2">
<div id="description_2"
class="col-sm-2 taskDescriptionCol">Description 2
</div>
<div id="colour_1"
class="col-sm-2 taskColourCol">Red
</div>
</div>
</div>
<button id="loopButton" type="button"
class="btn btn-sm btn-primary">Loop</button>
JS
$('#loopButton').on('click',function() {
var ids = [];
var row = $('.taskRow');
$.each( row, function() {
// get the id of each row and get the description and colour
// ids.push( push the id you got);
console.log("in loop" + row.html());
});
});
You can use jQuery's .map() to loop over the elements and create an array of extracted properties (demo):
$('#loopButton').on('click', function() {
var ids = [];
var rowsData = $('.taskRow').map(function(index, element) {
var $fields = $(this).find('div');
return {
id: this.id,
label: $fields.eq(0).text().trim(),
description: $fields.eq(1).text().trim()
};
}).toArray();
console.log(rowsData);
});
If you want to do it with plain javascript
var loopButton = document.getElementById("loopButton");
loopButton.addEventListener("click", function() {
let ids = [];
var rows = document.getElementsByClassName("taskRow");
Array.prototype.forEach.call(rows, function(r){
ids.push(r.id)
console.log(r.children[0].innerHTML)
})
console.log(ids);
});

react.js every nth item add opening tag or closing tag

I'm having trouble with this logic since react/jsx does not allow for non closing tags to be added to an array/child component. For example with bootstrap css I want to add a row for every 4 columns.
So the logic is as follows:
Add a opening row ex: <div className="row">, then loop inside this row and every loop append a column ex: <div className="column>{this.data}</div> when the loop reaches 4 check with if(i % 4 == 0) and add a closing </div> tag while adding new row tag <div className="row">;
The code below would work in another language but in react this is not doable since we push a closing tag and a opening tag (which is invalid jsx):
generateColumns(columns) {
let newColumns = [];
columns.forEach(function(column, idx) {
newColumns.push( <div className="column"> some data </div> );
if (idx % 4 == 0) {
// Here we end the row and start a new row, works in any other language.
newColumns.push( </div> <div className="row"> );
}
});
// This array now has the proper tags for opening a row every 4th item and closing it.
return newColumns;
},
render() {
return (
<div className="row">
{this.generateColumns(this.props.columns)}
</div>
)
}
The expected output would be:
<div class="row">
<div class="column">
Some data
</div>
<div class="column">
Some more data
</div>
<div class="column">
Other data
</div>
<div class="column">
Something else
</div>
</div>
<div class="row">
<div class="column">
Some data
</div>
<div class="column">
Some more data
</div>
<div class="column">
Other data
</div>
<div class="column">
Something else
</div>
</div>
//the above would be repeated and new rows would appear every 4 columns.
render() {
const rows = array_chunk(this.props.columns, 4)
return (
{
rows.map((row) => (
<div className="row">
{
row.map((col) => (
<div className="col">{ col }</div>
))
}
</div>
))
}
)
}
An example array_chunk (I recommend that you use lodash)
module.exports = function chunks(arr, size) {
if (!Array.isArray(arr)) {
throw new TypeError('Input should be Array');
}
if (typeof size !== 'number') {
throw new TypeError('Size should be a Number');
}
var result = [];
for (var i = 0; i < arr.length; i += size) {
result.push(arr.slice(i, size + i));
}
return result;
};
I actually just used arrays and react handled fine the rendering.
render() {
let rows = [],
cols = []
let index = 0
const totalCols = 20;
for (index; index < totalCols; index++) {
cols.push(<div class="col" key={index}/>)
if ((index + 1) % 4 == 0) {
rows.push(
<div class="row" key={index}>
{cols}
</div>
)
cols = []
}
}
return (
<div class="container">
{rows}
</div>
)
}

Categories

Resources