Appending data from api into DOM - javascript

const url = `https://catfact.ninja/fact?max_length=140`;
const getFact = () => {
return fetch('https://catfact.ninja/fact?max_length=140')
.then(res => res.json())
}
const createFactDiv = (fact) => {
const factContainer = document.createElement('div')
const setup = document.createElement('p')
setup.innerText = fact.fact
factContainer.append(setup)
return factContainer
}
const appendFact = (factDiv) => {
const factContainer = document.getElementById('factContainer')
factContainer.append(FactDiv)
}
document.addEventListener('DOMContentLoaded', () => {
})
getFact().then ((fact) => {
const FactDiv = createFactDiv(fact)
append.fact (FactDiv)
})
I have tried several things, fairly new to JS and it is tricky. I am trying to create an app that displays cat facts. I was seeing the DIV with the FACT inside correctly in the console.log in the elements of the DOM, but now I don't see it and I keep seeing
Uncaught (in promise) ReferenceError: append is not defined
Any idea what to do? Much appreciated !

Yep, it's our old friend spelling errors! Here is some working code:
const url = `https://catfact.ninja/fact?max_length=140`;
const getFact = () => {
return fetch('https://catfact.ninja/fact?max_length=140')
.then(res => res.json())
}
const createFactDiv = (fact) => {
const factContainer = document.createElement('div');
const setup = document.createElement('p');
setup.innerText = fact.fact;
factContainer.append(setup);
return factContainer
}
const appendFact = (factDiv) => {
const factContainer = document.getElementById('factContainer');
factContainer.append(factDiv);
}
//This is unused
/*
document.addEventListener('DOMContentLoaded', () => {
})
*/
getFact().then ((fact) => {
const factDiv = createFactDiv(fact);
appendFact(factDiv);
})
This is why it's important to consistently use camelCase:
In appendFact() you took a factDiv parameter but then tried to use FactDiv, which doesn't exist in that function
As noted by Robin, you typed append.fact(FactDiv) instead of appendFact(FactDiv)
This should be refactored to appendFact(factDiv) to stick with camelCase.
Also watch your spacing, and I like to have semicolons at the end of my lines also!

Related

How to get each item from a filtered array, without using a map for each item

I'm taking an array and filtering the value in a context:
const { responsible } = useResponsible()
const [ids, setIds] = useState([])
const filteredResponsible = responsible?.filter((resp) =>
ids.includes(resp.id)
)
The problem is that I need to make a map to get the corresponding value of each id, one by one. This ends up making the code too long:
const { filteredResponsible } = useResponsible
const responsibleName = filteredResponsible.map((resp) => resp.name)
const responsibleEmail = filteredResponsible.map((resp) => resp.email)
const responsibleAddress = filteredResponsible.map((resp) => resp.address)
...
And so on with each item in the array.
I'm using the React Hook Form's setValue to set the value in the inputs:
useEffect(() => {
setValue('name', `${responsibleName}`)
setValue('email', `${responsibleEmail}`)
setValue('address', `${responsibleAddress}`)
setValue('cep', `${responsibleCep}`)
setValue('district', `${responsibleDistrict}`)
setValue('city', `${responsibleCity}`)
setValue('state', `${responsibleState}`)
setValue('phone', `${responsiblePhone}`)
setValue('sex', `${responsibleSex}`)
}, [])
How can I make these maps smaller? Without having to make a map to get each item in the array?
There doesn't seem to be any reason to do those map calls on every render and to do them anywhere other than where you need them, since you only show using the result in a mount-only effect. Just do them there:
const { filteredResponsible } = useResponsible; // Is there really no `()` needed here?
useEffect(() => {
setValue("name", `${filteredResponsible.map(({name}) => name)}`);
setValue("email", `${filteredResponsible.map(({email}) => email)}`);
setValue("address", `${filteredResponsible.map(({address}) => address)}`);
// ...
}, []);
If you really need those distinct arrays on every render, unless you can change your data structures to be more amenable to your output I don't see you have a lot of options. You can at least avoid multiple loops through filteredResponsible:
const { filteredResponsible } = useResponsible; // ()?
const responsibleName = [];
const responsibleEmail = [];
const responsibleAddress = [];
for (const { name, email, address } of filteredResponsible) {
responsibleName.push(name);
responsibleEmail.push(email);
responsibleAddress.push(address);
}
And if that's really the case, you may want to avoid doing it on every render:
const { filteredResponsible } = useResponsible; // ()?
const { responsibleName, responsibleEmail, responsibleAddress } = useMemo(() => {
const responsibleName = [];
const responsibleEmail = [];
const responsibleAddress = [];
for (const { name, email, address } of filteredResponsible) {
responsibleName.push(name);
responsibleEmail.push(email);
responsibleAddress.push(address);
}
return { responsibleName, responsibleEmail, responsibleAddress };
}, [filteredResponsible]);

issue to load data from a .js file

I am trying to run a web page with that js file, for some reason, it doesn't want to work and when I try the console it says "Live reload enabled". Does anyone know how I can solve that issue?
.
const container = document.querySelector('.datalink')
let listdata = async() => {
let url = ' http://localhost:3000/indusboards';
const urlfetch = await fetch(url);
const urlfound = await urlfetch.json();
let template = '';
datafound.array.forEach(element => {
template += `
<div class ="element">
<p><small>${element.serialno}</small></p>
<p><small>${element.boardtest}</small></p>
<p><small>${element.testresul}</small></p>
<p><small>${element.serialno}</small></p>
<p><small>${element.testdate}</small></p>
<p><small>${element.testtime}</small></p>
<p><small>${element.boardlocation}</small></p>
.... more
</div>
`
})
container.innerHTML = template;
}
window.addEventListener('DOMContentLoarded', () => listdata());
You made a spelling mistake change your code to.
window.addEventListener('DOMContentLoaded', () => listdata());
Instead of
window.addEventListener('DOMContentLoarded', () => listdata());
or you could use
window.onload = () => {
listdata()
}
How about this?
const container = document.querySelector('.datalink')
let listdata = async() => {
let url = ' http://localhost:3000/indusboards';
const urlfetch = await fetch(url);
const urlfound = await urlfetch.json();
let template = '';
datafound.array.forEach(element => {
template += `
<div class ="element">
<p><small>${element.serialno}</small></p>
<p><small>${element.boardtest}</small></p>
<p><small>${element.testresul}</small></p>
<p><small>${element.serialno}</small></p>
<p><small>${element.testdate}</small></p>
<p><small>${element.testtime}</small></p>
<p><small>${element.boardlocation}</small></p>
.... more
</div>
`
})
container.innerHTML = template;
}
window.addEventListener('DOMContentLoaded', () => listdata());

Get the variable data/result from the promise in React JS after running it through map

I want the result of activeCustomers array inside the last then but I keep getting an error saying arrow function expects a return. Not sure how I can get activeCustomers?
const CreateCustomer = (storeData) => {
let activeOrganization = null;
storeData.Org
.getOrganization()
.then(function createCustomer(organization) {
activeOrganization = organization[0];
const dataArray= storeData.attributes;
activeOrganization
.createAttributes(
attributeType[0],
getSomeData(dimensions)
)
.then(function Properties(createdAttribute) {
updateCustomerProperty(createdAttribute, attributeType[0]);
});
activeOrganization
.createAttributes(
attributeType[1],
getSomeData(dimensions)
)
.then(function Properties(createdAttribute) {
updateCustomerProperty(createdAttribute, attributeType[1]);
});
}).then(() => {
activeOrganization
.getCustomers()
.then((cusomters) => {
const activeCustomers = [];
cusomters.map((customer) => {
activeCustomers.push(customer);
});
return activeCustomers;
})
.then((activeCustomers) => {
console.log(activeCustomers);
});
});
};
//Now I want the result of activeCustomers array inside the last then but I keep getting an error saying arrow function expects a return. Not sure how I can get activeCustomers?
I want the result of activeCustomers array inside the last then but I keep getting an error saying arrow function expects a return. Not sure how I can get activeCustomers?
In your example i think you received a warning. But still how to access to activeCustomers it depends on how you want to use it there are you storing it.
If you want to store it globally then you can store it like that
let activeCustomers;
....
.then((cusomters) => {
activeCustomers = [];
cusomters.map((customer) => {
activeCustomers.push(customer);
});
return activeCustomers;
})
But i think it's better to rewrite to async/await.
const CreateCustomer = async (storeData) => {
let activeOrganization = null;
const [activeOrganization] = await storeData.Org
.getOrganization();
const activeOrgPrs = attributeType.map(x => activeOrganization
.createAttributes(
x,
getSomeData(dimensions)
)));
const attrs = await Promise.all(activeOrgPrs);
attrs.forEach((attr, i) => {
updateCustomerProperty(attr, attributeType[i]);
})
const cusomters = await activeOrganization
.getCustomers();
return cusomters;
};
And you can use it like const customers = await CreateCustomer(someData);
or like CreateCustomer(someData).then((cusomters) => { activeCustomers = cusomters; return null;(if it keeps to return errors)});

React Hook not setting with useEffect

I'm using useEffect to fetch some data from Trello and set some states. First I grab the card I'm looking for and call setCard and setCardLocation. Everything is working fine. Then I get into my else case and no matter what I do setPublishDate will never be set, the loop continues to run. Why do all of these other hooks work but my last one doesn't? Thanks.
export default function Home(props) {
const [performedFetch, setPerformedFetch] = useState(false);
const [slug, setSlug] = useState(null);
const [cardLocation, setCardLocation] = useState(1);
const [card, setCard] = useState(null);
const [publishDate, setPublishDate] = useState(null);
const key = ''; // imagine these are here
const token = '';
useEffect(() => {
setSlug(
new URLSearchParams(window.location.search).get('slug')
);
if (!performedFetch && !!slug) {
fetch(`https://api.trello.com/1/lists/${listId}/cards?key=${key}&token=${token}`)
.then(response => response.json())
.then(data => {
setPerformedFetch(true);
data.forEach((c, index) => {
if (c.desc.includes(slug)) {
setCard(c)
setCardLocation(index + 1)
} else if (!publishDate && index > cardLocation) {
console.log(publishDate); // why is this always null?? also runs multiple times
const name = c.name;
const frontHalf = name.split("/")[0].split(" ");
const month = frontHalf[frontHalf.length - 1];
const day = name.split("/")[1].split(")")[0];
setPublishDate(`${month}/${day}`);
}
});
});
}
});
As already mentioned by #TaghiKhavari, you should have two useEffects (Multiple effects to separate concerns).
Also, it is important to optimize the performance by skipping effects by providing a dependency array as second argument to the useEffect. So the effect will only re-run if any of its dependencies would change.
First effect for slug:
useEffect(() => {
setSlug(
new URLSearchParams(window.location.search).get('slug')
);
}, []) // Note: Remove "[]" if you want to set slug at each update / render Or keep it if you want to set it only once (at mount)
Second effect to fetch and set card and other details:
useEffect(() => {
if (!performedFetch && slug) {
fetch(
`https://api.trello.com/1/lists/${listId}/cards?key=${key}&token=${token}`
)
.then((response) => response.json())
.then((data) => {
setPerformedFetch(true)
// Note: if there can be only ONE matching card
const index = data.findIndex((card) => card.desc.includes(slug))
if (index > -1) {
const card = data[index]
setCard(card)
setCardLocation(index + 1)
const name = card.name
const frontHalf = name.split('/')[0].split(' ')
const month = frontHalf[frontHalf.length - 1]
const day = name.split('/')[1].split(')')[0]
setPublishDate(`${month}/${day}`)
}
// Setting State in a LOOP? is a problem
/*
data.forEach((card, index) => {
if (card.desc.includes(slug)) {
setCard(card)
setCardLocation(index + 1)
} else if (!publishDate && index > cardLocation) {
const name = card.name
const frontHalf = name.split('/')[0].split(' ')
const month = frontHalf[frontHalf.length - 1]
const day = name.split('/')[1].split(')')[0]
setPublishDate(`${month}/${day}`)
}
})*/
})
}
}, [slug, performedFetch])
Set states may be async to improve performance:
So, you should not set states in a loop as you are doing currently. If you must iterate through a loop and set all or few elements of the array in state, you can loop through the array and push all relevant items in a local array variable and set it to state after loop ends. Hope it helps!
It's because usually react states updates asynchronously and at the time you're checking for slug it hasn't set yet
you need to do something like this:
function Home(props) {
const [performedFetch, setPerformedFetch] = useState(false);
const [slug, setSlug] = useState(null);
const [cardLocation, setCardLocation] = useState(1);
const [card, setCard] = useState(null);
const [publishDate, setPublishDate] = useState(null);
const key = ""; // imagine these are here
const token = "";
useEffect(() => {
setSlug(new URLSearchParams(window.location.search).get("slug"));
});
useEffect(() => {
console.log(slug)
if (!performedFetch && !!slug) {
fetch(`https://api.trello.com/1/lists/${listId}/cards?key=${key}&token=${token}`)
.then(response => response.json())
.then(data => {
setPerformedFetch(true);
data.forEach((c, index) => {
if (c.desc.includes(slug)) {
setCard(c)
setCardLocation(index + 1)
} else if (!publishDate && index > cardLocation) {
console.log(publishDate); // why is this always null?? also runs multiple times
const name = c.name;
const frontHalf = name.split("/")[0].split(" ");
const month = frontHalf[frontHalf.length - 1];
const day = name.split("/")[1].split(")")[0];
setPublishDate(`${month}/${day}`);
}
});
});
}
}, [slug, performedFetch])
}

Making a web-crawler to have loop

I tried to make my web-crawler to have a loop to crawl the webpage from 1 to around 500. But the result does not include any directed one but to return an only void array.
This code is based on cheerio, jQuery, and axios. JavaScript.
const axios = require("axios");
const cheerio = require("cheerio");
const log = console.log;
const getHtml = async() => {
var i=0
while (i<493){
try {
return await axios.get("https://playentry.org/ds#!/qna?sort=created&rows=20&page="+i);
} catch (error) {
console.error(error);
}
}
};
getHtml()
.then(html => {
let ulList = [];
const $ = cheerio.load(html.data);
const $bodyList = $("div.discussContentWrapper div.discussListWrapper table.discussList").children("tr.discussRow");
$bodyList.each(function(i, elem){
ulList[i] = {
title:$(this).find('td.discussTitle div.discussTitleWrapper'),
writer:$(this).find('td.discussTitle td.discussViewCount'),
viewcount:$(this).find('td.discussTitle td.discussViewCount'),
likecount:$(this).find('td.discussTitle div.discussLikeCount'),
date:$(this).find('td.discussTitle td.discussDate'),
};
});
const data = ulList.filter(n => n.title);
return data;
})
.then(res => log(res));
The output is '''[]''' or '''[ [] ]''' with no real outputs.
Thanks for your help in advance.

Categories

Resources