How to make API calls in Vanilla JS - javascript

Am building a weather app using vanilla JS and weatherbit rapid API, but whenever I run the program, it logs an error Can not read properties of undefined (reading 'temp')
const tempValue = document.getElementsByClassName('temp')
// console.log(cityName)
const options = {
method: 'GET',
headers: {
'X-RapidAPI-Key': '************************************',
'X-RapidAPI-Host': 'weatherbit-v1-mashape.p.rapidapi.com'
}
}
document.getElementById('submit').addEventListener('click', e => {
e.preventDefault()
fetch(
'https://weatherbit-v1-mashape.p.rapidapi.com/forecast/3hourly?lat=35.5&lon=-78.5',
options
)
.then(response => response.json())
.then(data => {
let tempval = data['temp']
tempValue.innerHtml = tempval
})
.catch(err => console.error(err))
})

pls consult the docs.
https://rapidapi.com/weatherbit/api/weather
response object structure is:
{
country_code:"US",
lon:-78.5,
data: [...],
city_name:"Four Oaks",
lat:35.5,
timezone:"America/New_York",
state_code:"NC",
}
To access 'temp'. use `
fetch(
'https://weatherbit-v1-mashape.p.rapidapi.com/forecast/3hourly?lat=35.5&lon=-78.5',
options
).then(response => {
const someItemIndex = 0;
console.log(response.data);
const tempval = response.data[someItemIndex].temp
tempValue.innerHtml = tempval
})
.catch(err => console.error(err))
there is no temp in response. and there is no any field 'temp' in data. Temp is defined only on iterable items of data array.

After some advice I received from this platform, I have managed to modify the code and it's working perfectly. The problem was in the way I was accessing the fields from the JSON. I am new to APIs and this is an excellent start for me thank you.
Modified Code
const tempValue = document.querySelector('.temp')
const cityName = document.querySelector('.city_name')
const humid = document.querySelector('.humidity')
const weatherValue = document.querySelector('.weather')
// console.log(cityName)
const options = {
method: 'GET',
headers: {
'X-RapidAPI-Key': '30583b6ad4msh649637ae1b0f6d3p1edde0jsn53b7839146a2',
'X-RapidAPI-Host': 'weatherbit-v1-mashape.p.rapidapi.com'
}
}
document.getElementById('submit').addEventListener('click', e => {
e.preventDefault()
fetch(
'https://weatherbit-v1-mashape.p.rapidapi.com/forecast/3hourly?lat=35.5&lon=-78.5',
options
)
//Modified code
.then(response => response.json())
.then(response => {
const someItemIndex = 0
console.log(response.data)
const tempval = response.data[someItemIndex].temp
const cityval = response.city_name
const weatherval = response.data[someItemIndex].weather.description
// console.log(tempval)
tempValue.innerHTML = `<h3>Temperature: </h3>${tempval}&#x2103`
weatherValue.innerHTML = `<h3>Weather Description: </h3>${weatherval}`
cityName.innerHTML = `<h3>City Name: </h3>${cityval}`
})
.catch(err => console.error(err))
})

Related

Returns an empty array

I am trying to get the data from this endpoint but I am getting an empty array. Can you help me with this? thanks
I've been trying to do it, with the other methods I have I can get the corresponding data.
I tried several ways but still can't find a solution.
http://localhost:8081/getmnemonicsandtagsforabm this is the methood
const DataTable = () => {
const provider = useContext(AppContext);
let [editServiceStatus, setEditServiceStatus] = useState(false);
let [configServiceStatusButton, setConfigServiceStatusButton] =
useState(false);
let [serviceItem_selected, setServiceItem_selected] = useState([]);
let [fetchServiceDetail, setFetchServiceDetail] = useState([]);
let sessionID = localStorage.getItem("session_id");
const [array_services, setArray_services] = useState({ khad_services: [] });
const [array_services2, setArray_services2] = useState({ khad_services: [] });
const [active_dropdown, setActive_dropdown] = useState(false);
const [active_serviceConfig, setActive_serviceConfig] = useState(false);
useEffect(() => {
let session_id = {
session_id: sessionID,
};
fetch("http://localhost:8081/getservicelist", {
method: "POST",
body: JSON.stringify(session_id),
})
.then((res) => res.json())
.then((data) => {
//console.log(`****__ data: __****: `, data);
localStorage.setItem("array_services", JSON.stringify(data));
setArray_services(data);
})
.catch((err) => console.log(err));
}, []);
useEffect(() => {
let session_id = {
session_id: sessionID,
};
fetch("http://localhost:8081/getmnemonicsandtagsforabm", {
method: "POST",
body: JSON.stringify(session_id),
})
.then((res) => res.json())
.then((data) => {
console.log(`****__ data:__****: `, data);
localStorage.setItem("mnemonicsAndTags", JSON.stringify(data));
localStorage.setItem("mnemonics", JSON.stringify(data.mnemonics));
localStorage.setItem("tags", JSON.stringify(data.tags));
localStorage.setItem("tagsForMnemonics", JSON.stringify(data.tagsForMnemonics));
setArray_services(data);
})
.catch((err) => console.log(err));
}, []);
I await the return of the array accordingly

MongoDB server Value cannot update?

I am making a simple website.. i use react, MongoDB, JavaScript. My Problem is when click delivered button the quantity increase i update my UI and MongoDB Server. When Code is run in MongoDB server quantity is null..
Here is the code
const handleDelivered = data => {
const { quantity, ...rest } = bookItem;
const quantity1 = parseInt(bookItem.quantity) - 1;
const quantityStr = quantity1.toString();
const newQuantity = { quantity: quantityStr, ...rest }
setBookItem(newQuantity);
const getquantity = bookItem.quantity;
console.log(getquantity);
const updateQuantity = { getquantity };
const url = `http://localhost:5000/items/${itemsId}`;
fetch(url, {
method: 'PUT',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify(updateQuantity)
})
.then(res => res.json())
.then(data => {
console.log(data);
})
}

Using Axios to post a joke on click ( 1 at a time )

I could use some help.
I have a button and on click, it generates a joke using dad jokes API and Axios. However, I can't figure out how to get rid of the old joke when I click on the button again. Here is my code. Thanks
let button = document.querySelector('button')
button.addEventListener("click", getJoke)
function getJoke() {
const p = axios
.get('https://icanhazdadjoke.com/', { headers: { "Accept": "text/plain" },
})
.then((response) => {
const joke = response.data
const jokeContainer = document.querySelector('.joke');
const blockquoteEl = document.createElement('blockquote');
blockquoteEl.append(joke);
jokeContainer.appendChild(blockquoteEl);
})
.catch((error) => {
const jokeContainer = document.querySelector('.joke');
jokeContainer.innerText = 'Joke not found :(';
});
}
<div class="joke">
<button>Click if you want a cringe joke</button>
</div>
What you should do is use the functions inherited by dom elements to delete de child node:
<body>
<div class="joke">
<button>Click if you want a cringe joke</button>
</div>
<script>
let button = document.querySelector('button');
button.addEventListener("click", getJoke);
function getJoke(){
const p = axios.get('https://icanhazdadjoke.com/', { headers: { "Accept": "text/plain" }
}).then((response) => {
const joke = response.data
const jokeContainer = document.querySelector('.joke');
jokeContainer.removeChild(jokeContainer.childNodes[2]);
const blockquoteEl = document.createElement('blockquote');
blockquoteEl.append(joke);
jokeContainer.appendChild(blockquoteEl);
}).catch((error) => {
const jokeContainer = document.querySelector('.joke');
jokeContainer.innerText = 'Joke not found :(';
});
}
</script>
</body>
you need to store the incoming jokes in ana array to check the duplicates. try this
function getJoke() {
const p = axios
.get('https://icanhazdadjoke.com/', { headers: { "Accept": "text/plain" },
})
.then((response) => {
const joke = response.data
const jokesArr = [];
// stores joke history
jokesArr.push(joke);
// checkes the repeated joke in jokes history
const jokeCheck = (joke) => {
const currentItemCount = jokesArr.filter(val => val=== joke).length;
if(currentItemCount > 0) {
p();
}
return joke;
}
const currentJoke = jokeCheck(joke);
const jokeContainer = document.querySelector('.joke');
const blockquoteEl = document.createElement('blockquote');
blockquoteEl.append(currentJoke);
jokeContainer.appendChild(blockquoteEl);
})
.catch((error) => {
const jokeContainer = document.querySelector('.joke');
jokeContainer.innerText = 'Joke not found :(';
});
}

How to make multiple Fetch calls

I have multiple API calls with fairly lengthy, yet similar, response/error handling for each call.
What is the best non-repetitive ways to make multiple independent api calls that update state using fetch?
Copying and pasting 40+ instances of fetch doesn't seem right.
I want to avoid doing this ....
fetch(url,options)
.then((response) => {
// ...
return response.json
})
.then((data) => {
setState(data)
//...
})
.catch((err) => {
//Error logic here
})
Here's what I've done so far:
I made (found and modified) a useFetch hook...
useFetch.ts
//Only calls fetch() when .load() is called.
const useFetch = (path : string, HttpMethod : string, dependencies : any = [] , body : {} | undefined = undefined) => {
const history = useHistory()
const [response, setResponse] = useState<any>({});
const [error, setError] = useState<string>("");
const [isLoading, setIsLoading] = useState<boolean>(false);
const [controller, setController] = useState(2)
const [isReady, setIsReady] = useState<any>(false)
const load = ():void => {
setError("")
//This prevents useEffect from triggering on declaration.
if (isReady) {
//Math.random() is just to get useEffect to trigger.
setController(Math.random())
}
}
const token = localStorage.getItem("token");
let requestOptions:any = {
method: HttpMethod,
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "* always",
Authorization: "Token " + token,
},
};
if (body !== undefined) {
requestOptions["body"] = {
body: JSON.stringify(body)
}
}
const URI = BASE_URI + path
useEffect(() => {
const fetchData = async () => {
if (controller !== 2) {
setIsLoading(true);
try {
const res = await fetch(URI, requestOptions);
const json = await res.json();
if (json?.action == "ENFORCE_BILLING" ) {
history.push(BILLING_CREDENTIALS_PATH, { enforceBillingPopUp: true });
}
if (json?.action == "ENFORCE_SMS_CONFIRMATION") {
// Should we log user out, as well?
history.push(CONFIRMATION_CODE_PATH)
}
if (res.ok) {
setResponse(json);
setIsLoading(false)
} else {
setError(json)
setIsLoading(false)
}
} catch (err) {
setError(err);
// Error logic here...
}
}
}
};
fetchData()
setIsReady(true)
}, [controller, ...dependencies]);
return { response, setResponse ,error, isLoading, load, isReady };
};
Component.tsx
//Inside react functional component...
// Prepares to fetch data from back-end
const data1 = useFetch(PATH1, "GET");
const data2 = useFetch(PATH2, "GET");
const data3 = useFetch(PATH3, "GET");
useEffect(() => {
// Initial on load data fetch
// .load() fetches data
data1.load();
data2.load();
data3.load();
}, [activeReservations.isReady]);
// Sort data depending on sort selection
...
Is useFetch considered bad practice? What are the advantages of using Redux, instead?
Any help would be greatly appreciated. Thanks.

How to remove a part of html on live in React

I've got components in my react app,
First:
const App = () => {
const [tasks, setTasks] = useState([])
useEffect(() =>{
getTasks(data => setTasks(data))
}, [])
const onNewTask = task => {
setTasks(prev => ([
...prev,
task
]))
}
const onRemoveTask = () => {
setTasks(prev => ([
...prev,
]))
}
return (
<>
<NewTask add={onNewTask}/>
<Task tasks={tasks} remove={onRemoveTask}/>,
</>
)
}
This component renders two childrens:
In comp newTask there is a method where user can add a new task, the method:
const addNewTask = e => {
e.preventDefault();
fetch(`${API_URL}/tasks`, {
method: 'POST',
headers: {
Authorization: API_KEY,
"Content-Type": "application/json"
},
body: JSON.stringify(inputs)
})
.then(response => response.json())
.then(data => add(data.data))
.catch(e => console.warn(e))
}
It works fine, user adds a tasks, and it automatically appears in HTML thanks to onNewTask method in App component.
My problem is something similar, but in case of removing the task, I've got a method in Task component:
const handleDeleteTask = e => {
e.preventDefault();
const taskToRemove = e.target.id;
console.log(taskToRemove)
taskToRemove ?
fetch(`${API_URL}/tasks/${taskToRemove}`, {
method: 'DELETE',
headers: {
Authorization: API_KEY,
"Content-Type": "application/json",
},
})
.then(remove())
.catch(err => console.warn(err))
:
console.log('Error')
}
It removes a task, but user needs to refresh page to make the task disappear from HTML.
I know that my method isn't correct. Can someone please tell me how do it?
Thanks in advance.
you need to update the task array and set the same in setTasks.
const onRemoveTask = (id) => {
const newTaskList = tasks.filter(item.id != id)
setTasks(newTaskList)
}

Categories