querySelectorAll return an empty object - javascript

I'm using Chromy framework to scrap a page, so, this is the html:
<ul class="a">
<li class="b"></li>
<li class="b"></li>
<li class="b"></li>
<li class="b"></li>
</ul>
So, if I do on chrome console the selection like this:
document.querySelectorAll('.b')
It will return me a nodeList with 4 objects inside and that's right, but if I do the same selection inside chromy script it return an empty object with 4 empty objects { '0': {},'1': {},'2': {},'3': {}}.
Can you please help me to figure out why this is happening?
That's my Chromy script
chromy.chain()
.goto('https://localhost:8080/')
.evaluate(() => {
return document.querySelectorAll('.b');
})
.result((r) => console.log(r))
.end()
.then(() => chromy.close());

Related

Get index of an element from a NodeList

I have a simple list:
<ul id="list">
<li id="item-1">1</li>
<li id="item-2" style="display: none">2</li>
<li id="item-3">3</li>
<li id="item-4">4</li>
<li id="item-5">5</li>
</ul>
And need to get index of a specific item disregarding hidden items.
var list = document.getElementById('list');
var items = list.querySelectorAll('li:not([style*="display: none"])');
I try to convert NodeList in Array:
var list_items = Array.from(items);
But don't known how to run something like that: list_items.indexOf('item-3')
https://codepen.io/marcelo-villela-gusm-o/pen/RwNEVVB?editors=1010
You can make a function to find the id you need in a list you want, passing two parameters, that way you can use this function dynamically.
Based on id, inside the function just need to use .findIndex() that returns the index or -1 if not found.
See here:
var list = document.getElementById('list');
var items = list.querySelectorAll('li:not([style*="display: none"])');
var list_items = Array.from(items);
function getIndexById(idToSearch, list){
//ES6 arrow function syntax
return list.findIndex(elem => elem.id == idToSearch)
//normal syntax
//return list.findIndex(function(elem) {return elem.id == idToSearch})
}
console.log("found at index: ", getIndexById("item-3", list_items))
<ul id="list">
<li id="item-1">1</li>
<li id="item-2" style="display: none">2</li>
<li id="item-3">3</li>
<li id="item-4">4</li>
<li id="item-5">5</li>
</ul>
Not exactly related to the question, but if possible, I would suggest you to change your HTML to remove that inline style of display: none and change it to a class, (e.g: class='hidden'), it would be better for your .querySelector when using :not, for example: li:not(.hidden), since any space in your inline style can break your selector. ("display:none" != "display: none", spot the space)
Maybe like this:
var item = list_items.find(function(item) {
return item.id === "item-3";
});
I would recommend using :not(.hidden) instead of "grepping" for a match on the style tag. Then, simply find the index after casting the NodeList to an array.
For the Vue.js inclined, see this fiddle: https://jsfiddle.net/634ojdq0/
let items = [...document.querySelectorAll('#list li:not(.hidden)')]
let index = items.findIndex(item => item.id == 'item-4')
console.log('item-4 index in visible list is', index)
.hidden {
display: none;
}
<ul id="list">
<li id="item-1">1</li>
<li id="item-2" class="hidden">2</li>
<li id="item-3">3</li>
<li id="item-4">4</li>
<li id="item-5">5</li>
</ul>
Maybe you can use map. First you can create an object with id and value. Then use map function to create array of this object. Then you can access it with foreach, when id = 'item-3'.

Loop through Object in JSX

On a JSX file, I need to loop through two levels of an Object to render the information each inner Array stores. It looks something like: Object > Object > Array
My data is structured this way:
const data = {
group1: {
subgroup1: [{...}, {...},{...}],
...
},
...
}
So I'm trying to acomplish something like this:
return (
<ul>
for (group in data) {
<li>Group Name
<ul>
for(subgroup in group) {
<li>Subgroup Name
<ul>
subgroup.map()
</ul>
</li>
}
</ul>
</li>
}
</ul>
)
I know for loops are not allowed inside a JSX file but converting my object into multiple Arrays doesn't seem right either since I have no idea how many items might be coming form my API.
I solved this using Herohtar suggestion, extracting the key/value of each of the parent Objects in an Array format:
{
Object.entries(data).map(group => (
<ul key={group[0]}>
<li>{group[0]}
<ul>
{
Object.entries(group[1]).map(subgroup => (
<ul key={subgroup[0]}>
<li>{subgroup[0]}
<ul>
{
subgroup[1].map(item => (
<li key={item.code}>{item.name}</li>
)
)
}
</ul>
</li>
</ul>
)
)
}
</ul>
</li>
</ul>
)
)
}
I wish there was a more elegant way of doing this though.

Get data-attribute value and HTML in array

I have the following tag in my html and I need to select the data-id value and the inner html value into an array.
How can I achieve this in either Jquery or Javascript
<li class="dual-listbox__item" data-id="1">Politieacademie</li>
<li class="dual-listbox__item" data-id="3">IBM</li>
<li class="dual-listbox__item dual-listbox__item--selected" data-id="5">Energias de Portugal</li>
You can use .map() along with .get() to convert it to basic array
var arr = $('li.dual-listbox__item').map(function() {
return {
id: $(this).data('id'),
text: $(this).html()
};
}).get();
console.log(arr)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li class="dual-listbox__item" data-id="1">Politieacademie</li>
<li class="dual-listbox__item" data-id="3">IBM</li>
<li class="dual-listbox__item dual-listbox__item--selected" data-id="5">Energias de Portugal</li>
</ul>
Select the elements, loop them using map and you got your array. Below will return an array of objects holding the data you want
const res = Array.from(document.querySelectorAll('.dual-listbox__item')).map(e => ({
dataId: e.dataset.id,
innerHTML: e.innerHTML
}));
console.log(res);
<li class="dual-listbox__item" data-id="1">Politieacademie</li>
<li class="dual-listbox__item" data-id="3">IBM</li>
<li class="dual-listbox__item dual-listbox__item--selected" data-id="5">Energias de Portugal</li>
You can use $('.dual-listbox__item').each() to achieve this:
var dataId = [];
var nHTML = [];
$('.dual-listbox__item').each(function(){
dataId.push($(this).data('id'));
nHTML.push($(this).text());
});
console.log(dataId);
console.log(nHTML);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<li class="dual-listbox__item" data-id="1">Politieacademie</li>
<li class="dual-listbox__item" data-id="3">IBM</li>
<li class="dual-listbox__item dual-listbox__item--selected" data-id="5">Energias de Portugal</li>

Dynamic HTML navigation bar from array

I outputted the following array to the equivalent JavaScript JSON variable, and I tried to create a dynamic based navigation bar.
$navArray = array(
array('id'=>1,'parent'=>0,'text'=>'1A','href'=>'1a'),
array('id'=>2,'parent'=>1,'text'=>'2B','href'=>'2b'),
array('id'=>3,'parent'=>1,'text'=>'3C','href'=>'3c'),
array('id'=>4,'parent'=>2,'text'=>'4D','href'=>'4d'),
array('id'=>5,'parent'=>2,'text'=>'5E','href'=>'5e'),
array('id'=>6,'parent'=>5,'text'=>'6F','href'=>'6f'),
array('id'=>7,'parent'=>5,'text'=>'7G','href'=>'7g'),
array('id'=>8,'parent'=>3,'text'=>'8H','href'=>'8h'),
);
The script (JavaScript/jQuery) should get the array and returns HTML based on the parent 'id' as follows:
<ul>
<li>
1A
<ul>
<li>
2B
<ul>
<li>
4D
</li>
<li>
5E
<ul>
<li>
6F
</li>
<li>
7G
</li>
</ul>
</li>
</ul>
</li>
<li>
3C
<ul>
<li>
8H
</li>
</ul>
</li>
</ul>
</li>
<ul>
The HTML screen result should look like this:
I tried doing something... but that didn't work.
$('li.dropdown').hover(
function(){
$(this).find('ul').slideDown();
},
function(){
$(this).find('ul').slideUp();
});
How do you dynamically create a multi dimensional level HTML navigation bar as described?
Sounds like a classic case for recursion, can you change the array objects to include their own children?
$navArray = array(
array('id'=>1,'text'=>'1A','href'=>'1a', 'children' => array(
array('id'=>2,'text'=>'2B','href'=>'2b', 'children' => array(
array('id'=>4,'text'=>'4D','href'=>'4d'),
array('id'=>5,'text'=>'5E','href'=>'5e', 'children' => array(
array('id'=>6,'text'=>'6F','href'=>'6f'),
array('id'=>7,'text'=>'7G','href'=>'7g'),
)),
)),
array('id'=>3,'text'=>'3C','href'=>'3c', 'children' => array(
array('id'=>8,'text'=>'8H','href'=>'8h')
)),
)),
);
Then if you output your array into JS (let arr = <?=json_encode($navArray)?>), you can feed it into your function which will run recursively through the children, something similar to this should work:
function createMenuItems(arr) {
let output = '<ul>'
for (let item of arr) {
output += `<li><a id="${item.id}" href="${item.href}">${item.text}</a></li>`
if (item.children && item.children.length) {
output += createMenuItems(item.children);
}
}
output += '</ul>'
return output
}

Get object key in ng-repeat

If I have an object like the following:
languages = {
"ar":{
"name":"Arabic",
"nativeName":"العربية"
},
"bg":{
"name":"Bulgarian",
"nativeName":"български език"
},
"ca":{
"name":"Catalan; Valencian",
"nativeName":"Català"
}...
}
And I loop through it in a list like so:
<ul>
<li ng-repeat="lang in languages"><a ng-click="select(lang)">{{lang.nativeName}}</a></li>
</ul>
Is there a way to get the object key in the select function without also putting the key in the object itself?
i.e:
languages = {
"ar":{
"name":"Arabic",
"nativeName":"العربية",
"key":"ar"
},
Thanks.
You could do like below:
<ul>
<li ng-repeat="(key, lang) in languages"><a ng-click="select(key)">{{lang.nativeName}}</a></li>
</ul>

Categories

Resources