How to check value of innerText if is null - javascript

I am developing a web scrapping and I am trying to solve latest problems with this.
In this case I need to check if innerText is null inside loop.
for(var j = 0; j<linkPlayersNew.length;j++){
var stats = [];
for (let i = 2; i <= 23; i++) {
const values = await page.evaluate((nth,nth2) => {
const test= parseInt(nth);
const test2= parseInt(nth2);
return document.querySelector('div.ui-table__row:nth-child('+test2+') > div:nth-child('+test+')').innerText;
},i,j+1);
stats.push(values);
}
data.push(stats);
}
console.log(data);
This works correct but I need to check if innerText is not null inside loop.

Related

Issue with recursive function converting dom element to json

I have a recursivce function that takes a dom tree and converts it to JSON.
However I want to exclude any nodes that have a specific data attribute data-exclude
const htmlToJSON = node => {
const exclude = node.attributes?.getNamedItem('data-exclude');
if (!exclude) {
let obj = {
nodeType: node.nodeType
};
if (node.tagName) {
obj.tagName = node.tagName.toLowerCase();
} else if (node.nodeName) {
obj.nodeName = node.nodeName;
}
if (node.nodeValue) {
obj.nodeValue = node.nodeValue;
}
let attrs = node.attributes;
if (attrs) {
length = attrs.length;
const arr = (obj.attributes = new Array(length));
for (let i = 0; i < length; i++) {
const attr = attrs[i];
arr[i] = [attr.nodeName, attr.nodeValue];
}
}
let childNodes = node.childNodes;
if (childNodes && childNodes.length) {
let arr = (obj.childNodes = []);
for (let i = 0; i < childNodes.length; i++) {
arr[i] = htmlToJSON(childNodes[i]);
}
}
return obj;
}
};
const parser = new DOMParser();
const { body } = parser.parseFromString(page, 'text/html');
let jsonOutput = htmlToJSON(body);
console.log(jsonOutput);
I am clearly missing something with the way I am excluding because when I log the results it is returning undefined instead of just excluding it.
It's most likely because you're not returning anything from htmlToJSON in the case of "exclude == true". Notice how your lambda function doesn't have a "return " in that case. So the function will by default return "undefined."
And if you fill an array element with "undefined" it becomes a sparse array. So those elements in the array with "undefined" values become interpreted as "empty" slots by console.log() when printing the contents of any array to the console.
Update: I tried your code and, yup, my explanation above is correct. However, if you don't care about implicitly returning undefined from your htmlToJSON(), then you can just modify your inner for loop:
for (let i = 0; i < childNodes.length; i++) {
let json = htmlToJSON(childNodes[i]);
json && arr.push(json);
}
This way, only if json is truthy, will it add an element to the arr array.
I tried this code with your original function, and also with a modified version that returns null if exclude == true, and both ways worked.
Here's a Codepen example.
Did not execute the code. As far as I can see htmlToJSON will return obj or undefined. If exclude is truthy, the function will return undef, thats what you are seeing.
Change your for loop:
for (let i = 0, temp; i < childNodes.length; i++) {
temp = htmlToJSON(childNodes[i]);
temp && (arr[i] = temp);
}
that way you make sure if temp is defined you assign, otherwise not.
Another option is to use Array.prototype.filter on the resultant array.

Array is empty after a foreach loop (async/await)

I'm trying to retrieve an array of cards for a project. However, in my function, the final contacts array returns an empty array.
I know that, because I have an async call to another funcion inside the forEach loop, the loop doesn't execute as intended. However, I'm very newbie when it comes to deal with this issues, so I want to ask you what's the best approach to deal with this.
This is my code:
export const extractsIDSForUser = async (currentUser: User) : Promise <Object> => {
let contactCards = currentUser.contacts;
const contacts = [];
const usersRef = await firebase.firestore().collection('Users').get();
const usersSnapshot = usersRef.docs.map(doc => doc.data());
contactCards.forEach(async folder => {
const ids = [];
folder.forEach(contact => {
ids.push(contact);
});
for (let i = 0; i < ids.length; i +=1) {
const contact = ids[i];
for (let j = 0; j < usersSnapshot.length; j += 1) {
const userId = usersSnapshot[j].id;
// Async call to function
const cardsFromUser = await extractCardsFromUser(userId);
const arrayCards = Object.values(cardsFromUser);
if (arrayCards.length > 0) {
for (let j = 0; j < arrayCards.length; j += 1) {
const arrayId = arrayCards[j].id;
const sameCardId = arrayId === contact;
if (sameCardId) {
// Where I insert the values into the array
contacts.push(arrayCards[j]);
}
}
}
}
}
});
// this is empty
return contacts;
}
What will be the best approach to deal with this?
I think you have already found a solution, but I had a similar problem and found this article quite helpful.
You could use a traditional for (const contactCard of contactCards) and it will work, but it will be less efficient than using a Promise.all approach.

How to extract the month values from the res.body.results array of objects using JS Array map()

Also trying to get that custom code that extracts the months from the string with regex in my code snippet. I believe I am close but not quite. Console log is returning "undefined" values for the key/value pairs and 0 for the months when it should return 60. Any thoughts on how to restructure this would be very much appreciated! I am trying to get the highest number of months/years from an array and set it to a property in HubSpot. Thank you kindly for any advice on how to properly configure to get correct values.
hubspotClient.crm.lineItems.batchApi.read({
inputs,
properties: ['hs_recurring_billing_period', 'recurringbillingfrequency',]
})
.then(res => {
const inputs = res.body.results.map(result => {
result.properties.recurringbillingfrequency =
result.properties.recurringbillingfrequency;
result.properties.months = Number(result.properties.months);
return { term: hs_recurring_billing_period, frequency: recurringbillingfrequency };
})
console.log(inputs);
let term = 0;
const largestNum = (years) => {
//let term = 0;
for (let i=0; i <res.body.results.length; i++){
let { recurringbillingfrequency, hs_recurring_billing_period } =
res.body.results[i].properties;
console.log(recurringbillingfrequency, hs_recurring_billing_period)
if(recurringbillingfrequency = "Annually")
{
let months = Number(hs_recurring_billing_period.replace(/\D/g, ''));
let years = months / 12;
// let term = 0;
if (years[i] > term) {
term = years[i];
}
}
}
return term;
}
console.log(largestNum(term));
return;
The map function looks strange to me:
const inputs = res.body.results.map(result => {
result.properties.recurringbillingfrequency = result.properties.recurringbillingfrequency;
result.properties.months = Number(result.properties.months);
return { term: hs_recurring_billing_period, frequency: recurringbillingfrequency };
})
within the scope of the mapping function, recurringbillingfrequency and hs_recurring_billing_period in the return object are not defined. Would it work by replacing the return value with as so?
return {
hs_recurring_billing_period: result.properties.hs_recurring_billing_period,
recurringbillingfrequency: result.properties.recurringbillingfrequency
};
Also, I am not quite sure how this line is necessary:
result.properties.recurringbillingfrequency = result.properties.recurringbillingfrequency;
So either this loop will work and extract the months and set to years or you can use Lodash with one line of code.
let term = 0;
for (let i=0; i <inputs.length; i++){
let { recurringbillingfrequency, hs_recurring_billing_period } =
inputs[i];
console.log(recurringbillingfrequency, hs_recurring_billing_period)
if(recurringbillingfrequency.toLowerCase() === 'annually')
{
let months = hs_recurring_billing_period;
let years = months / 12.0;
/*
let highest = 0;
function getHighestTerm(values) {
for (let j=0; j < values.length; j++)
if (j === 0) {
highest = values;
} else if (highest > values[j]) {
highest = values[j];
}
return highest;
}
*/
term = _.max(_.map(inputs, 'hs_recurring_billing_period')) / 12.0;

Adding dynamic named Javascript object to an array with a for loop

Wondering if it is possible to use a loop to add dynamically named objects to an array, so I don't need to repeat the "push" on an array. Tks !!
let _objA0 = { "name":"regionId", "value":"myRegion" };
let _objA1 = { "name":"vdcId", "value":"myId" };
let _objA2 ... _objA100
let test = []
test.push(_objA0)
test.push(_objA1)
...
test.push(_objA100)
I guess it's the right time to use eval
let test = [];
for(let i = 0; i <= 100; i++) {
test.push(eval(`_objA${i}`));
}
You can access variables (with var keyword) by window object , try this:
var _objA0 = { "name":"regionId", "value":"myRegion" };
var _objA1 = { "name":"vdcId", "value":"myId" };
let test = [];
for(let i = 0; i < 2; i++){
test.push(window['_objA' + i]);
}
console.log(test)

Reading data from Firebase to Javascript

I am trying to list all data from Javascript keys Object when I put it in console log there is all information, but when I want to use InnerHTML I keep getting the first object only shown.
function gotData(data){
var scores = data.val();
var keys = Object.keys(scores);
for (var i = 0; i < keys.length; i++) {
var k = keys[i];
var pro = scores[k].result;
var doc = document.getElementById("result").innerHTML = pro;
}
}
In this case, it will give me only a result of first element from my Firebase
Thanks
Please check out this stackblitz-demo, looks like your missing one small thing if I am understanding what your expected outcome is.
onClick() {
const scores = [{
'one': 1
}, {
'two': 2
}, {
'three': 3
}, {
'four': 4
}, {
'five': 5
}];
var keys = Object.keys(scores);
for (let i = 0; i < keys.length; i++) {
const k = keys[i];
const pro = scores[k].result;
// here the += is what i think you're missing.
const doc = document.getElementById("example").innerHTML += k;
}
}
The issue is that you are overriding innerHTML each time. Instead, you need to append to the existing innerHTML. Change the last line to...
const doc = document.getElementById("example").appendChild(document.createTextNode(k))
appendChild is also much faster than setting innerHTML
.hasOwnProperty is how to see just your stored values. Does this help?
d = snap.val();
for (var k in d) {
if (d.hasOwnProperty(k)) {
if (isObject(d[k]){
console.log(k, d[k]);
} else {
console.log (k);
}
}
}
function isObject(obj) {
return obj === Object(obj);
}

Categories

Resources