How to deal with empty response in axios? - javascript

I use axios with vue.js to fetch data as unlimited pagination. It works fine expect when there is no data to render:
fetchData() {
this.loading = true
this.page++;
axios.get(this.BASE_URL + '/api/jokes/'+'?page='+this.page).then(
response =>
//how to exist if there is no data in the response?
this.jokes = response.data).catch(function (error) {
console.log(error);
});
I'm wondering how to stop rendering when we reached to the last page and there is no more data to display?
I've looked at the docs but could not find my answer.

Maybe introducing some basic flag logics. I have taken the freedom to assume, but you can always define your logic
fetchData() {
this.loading = true;
if (this.page > 0) {
axios.get(this.BASE_URL + '/api/jokes/page=' + this.page)
.then(response => {
const isDataAvailable = response.data && response.data.length;
this.jokes = isDataAvailable ? response.data : [];
this.page = isDataAvailable ? (this.page + 1) : 0;
})
.catch(function(error) {
console.error(error);
});
}
}

You could throw a custom error that will be catch by the catch method.
fetchData() {
this.loading = true
this.page++;
axios.get(this.BASE_URL + '/api/jokes/'+'?page='+this.page).then(
response => {
//how to exist if there is no data in the response?
if (!response.data || response.data.length == 0) {
const emptyDataError = new Error('Invalid data');
emptyDataError.statusCode = 500;
throw emptyDataError;
}
this.jokes = response.data;
}).catch(function (error) {
console.log(error);
});

Related

trying to store api responses in asyncstorage but I am unable to store it

here I have pasted code which is written class component for mobx state management and i am calling it to another file,the thing is I have above 450 api responses and it need to store locally so i have tried it but i am not getting any value nor the data stored in database pls help me out thanks in advance ..
class ProductStore {
constructor() {
makeAutoObservable(this);
}
screenWidth = width;
screenHeight = height;
headerHeight = 0;
isiOS = Platform.OS === 'ios';
isAndroid = Platform.OS === 'android';
isProductLoading = 'pending';
productData = [];
filterdData = [];
search = '';
isFlatlistRender = false;
setFields(eName, data) {
this[eName] = data;
console.log(eName, data);
}
getproductData = () => {
if (this.isProductLoading == 'loading') {
return true;
}
this.isProductLoading = 'loading';
this.productData = [];
let headers = new Headers();
headers.set(
'Authorization',
'Basic ' + encode('username:password'),
);
fetch('some_url', {
method: 'GET',
headers: headers,
})
.then(response => response.json())
.then(responseJson => {
console.log('.....', responseJson);
AsyncStorage.setItem(
'ACCESS_TOKEN',
JSON.stringify(responseJson),
err => {
if (err) {
console.log('an error');
throw err;
}
console.log('success');
},
).catch(err => {
console.log('error is: ' + err);
});
try {
const value = AsyncStorage.getItem('ACCESS_TOKEN');
if (value !== null) {
console.log(JSON.parse(value));
}
} catch (error) {}
this.productData = responseJson;
this.isProductLoading = 'done';
})
.catch(error => {
console.error(error);
this.isProductLoading = 'error';
});
};
}
export default new ProductStore();
AsyncStorage.getItem() returns a promise, not the value. So, just add a then block after the line AsyncStorage.getItem('ACCESS_TOKEN');. It would be like this
AsyncStorage.getItem('ACCESS_TOKEN').then(value => {
if (value !== null) {
console.log(JSON.parse(value));
}
}).catch(err => console.error(err));

How to prevent axios from posting before state is updated

I am having a problem that the post request is not sending the updated currentVideo state as setState seems to be nonblocking. How can i make axios wait for the state to be set?
const nextVideo = () => {
if (videoList.indexOf(currentVideo) < videoList.length - 1) {
setCurrentVideo(videoList[videoList.indexOf(currentVideo) + 1]);
setLoading(true);
axios
.post(`${BACK_PORT}/videos/download`, currentVideo)
.then(function (response) {
if (response.data) {
setLoading(false);
} else {
console.log("waiting...");
}
})
.catch(function (error) {
alert(error)
});
} else {
alert("This is the last video");
}
};
Use a variable and store the currentvideo value in it. Then use that variable at both the places,i.e., for setting up the state and making the axios call.
const nextVideo = () => {
if (videoList.indexOf(currentVideo) < videoList.length - 1) {
let currentVideo = videoList[videoList.indexOf(currentVideo) + 1] //change here
setCurrentVideo(currentVideo );
setLoading(true);
axios
.post(`${BACK_PORT}/videos/download`, currentVideo)
.then(function (response) {
if (response.data) {
setLoading(false);
} else {
console.log("waiting...");
}
})
.catch(function (error) {
alert(error)
});
} else {
alert("This is the last video");
}
};

Cannot set headers after they are sent to the client in node js during updating data

I am new to node.js developement and encountered an error.
First of all here the code inside controller.js.
exports.updateCar = async (req, res,next) => {
const {name} = req.fields
try {
await updateCarService(name,next, (data) =>{
if(data == null || data){
res.status(201).json({
status:true,
message:'updated',
data
});
return
}
})
next()
} catch(e) {
res.sendStatus(500) && next(e)
}
};
and here the method inside services.js.
function updateCars(existingCar,callback){
Car.find({name : existingCar.name}, function (err, docs) {
if (docs.length){
//callback('Car exists already',null);
callback(err,docs)
}else{
existingCar.save(function(err,carr){
console.log('-------',carr)
callback(err,carr);
});
}
});
}
const updateCarService = async (name,next,callback) => {
try{
return await Car.find({name : name},(err,existingCar) => {
if (!err && existingCar.length > 0){
existingCar[0].name = 'audi';
updateCars(existingCar[0],(err2,car) =>{
if (err2 || !car){
console.log('error updated car: ',err2);
}else{
console.log('car updated: ',car);
return callback(car)
}
return
});
}
else if (!err && existingCar.length == 0){
return callback(null)
}
})
}
catch(e){
console.log(error)
}
}
After updating data i get error that :
events.js:187
throw er; // Unhandled 'error' event
^
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
I have tried many possible ways to solve this issue but i couldn't got any solution.
Please help me to resolve this issue.Also if any of style of coding is not good then correct me.

ERROR TypeError: subscribe is not a function in Ionic 4

I am doing with Ionic News App. I have one problem with getting a response from the service file.
home.page.ts
getNews(): void {
this.loading = true;
this.language = localStorage.language;
this.checkForToken();
var userId = this.loggedInUser;
this._newsService.getAllNews().subscribe(
(res: any) => {
console.log("all news==========>", res)
this.loadNewsToPage(res, userId);
},
(err) => {
this.loading = false;
this.error = err;
});
}
news.service.ts
getAllNews(){
if(this.network.type == 'none' ){
console.log(JSON.parse(localStorage.getItem("newsArray")));
this.newsArray = JSON.parse(localStorage.getItem("newsArray"))
return this.newsArray;
}else{
return this.http.get(config.baseApiUrl + 'news?isApproved=APPROVED').pipe(
map((res) => {
this.newsArray = res['data'];
localStorage.setItem('newsArray',JSON.stringify(this.newsArray))
return this.newsArray;
}),
catchError(this.handleError));
}
}
Now the problem is when the network is 'none' it goes in 'if' condition in service file and return response from local storage. But it gives me below error when network is none.
ERROR TypeError: this._newsService.getAllNews(...).subscribe is not a
function
It works properly when it goes in else condition or when a network is present. Why like this?
Your getAllNews function isn't an Observable. So you can't subscribe to it. See the example below where you return an Observable for the first if condition and the second else condition. You need to close the Observable with observer.complete() after each next function.
getAllNews(): Observable<any>{
return new Observable(observer => {
if(this.network.type == 'none' ){
console.log(JSON.parse(localStorage.getItem("newsArray")));
this.newsArray = JSON.parse(localStorage.getItem("newsArray"))
observer.next(this.newsArray);
observer.complete();
} else{
this.http.get(config.baseApiUrl + 'news?isApproved=APPROVED').subscribe(
(result: object) => {
this.newsArray = result['data'];
localStorage.setItem('newsArray',JSON.stringify(this.newsArray))
observer.next(this.newsArray);
observer.complete();
},
(error) => {
observer.error(error);
});
}
});
}
You can now access the next block in your subscribe > result and the error block in subscribing> error.
this._newsService.getAllNews().subscribe(
(res: any) => { // observer.next() brings you here
console.log("all news==========>", res)
this.loadNewsToPage(res, userId);
},
(err) => { // observer.error() brings you here
this.loading = false;
this.error = err;
});

Object fetch same api endpoint

I'm creating two instances of this object on every page of my website. When it loads, it
the makes a fetch call to /cities.json for data, that it then stores in session storage.
Next time the object
is created (on another page), it checks session storage before calling the api endpoint, to prevent
needless data requests. However, when the object is first created it makes two calls to the /cities.json api - because two instances typehead exist.
Apart from moving the call to outside of the object creation, which I don't want to do, as other objects also require this same api
endpoint, and I'd like to find a pattern that could work for each.
Index.js
import Typeahead from '../typeahead'
var typeaheadElements = [].slice.call(document.getElementsByClassName('typeahead'));
if (typeaheadElements.length) {
typeaheadElements.map(function (element) {
new Typeahead(element);
});
}
Typeahead.js
import fetchPromise from '../utilities/fetchSetStorage.js';
function Typeahead(element) {
init.call(this);
function init() {
var input = element.getElementsByTagName('input')[0];
if (input) {
let citiesData = fetchPromise('./cities.json', 'citiesJson');
Promise.all([citiesData]).then(function(values) {
items = values[0];
element.getElementsByTagName('input')[0].removeAttribute('disabled');
});
input.addEventListener('input', handleChange.bind(this));
element.addEventListener('keydown', handleKeyDown.bind(this));
element.addEventListener('click', handleElementClick.bind(this));
document.addEventListener('click', handleDocumentClick.bind(this));
}
}
}
fetchSetStorage.js
export default function fetchPromise(url, storageKey) {
if(sessionStorage.getItem(storageKey)) {
let storageKeyVal = JSON.parse(sessionStorage.getItem(storageKey));
return storageKeyVal;
}
return fetch(url)
.then(function(response) {
if (response.status !== 200) {
console.log('Looks like there was a problem. Status Code: ' +
response.status);
return;
}
return response;
})
.then(response => response.json())
.then(response => {
sessionStorage.setItem(storageKey, JSON.stringify(response))
return response;
})
.catch(function(err) {
console.log('Fetch Error :-S', err);
})
}
function Typeahead(element) {
init.call(this);
function init() {
var input = true;
if (input) {
console.log('input')
let citiesData = fetchPromise('/echo/json/', 'citiesJson');
Promise.all([citiesData]).then(function(values) {
items = values[0];
console.log(values);
});
}
}
}
function fetchPromise(url, storageKey) {
if (sessionStorage.getItem(storageKey)) {
let storageKeyVal = JSON.parse(sessionStorage.getItem(storageKey));
return storageKeyVal;
}
return fetch(url)
.then(function(response) {
if (response.status !== 200) {
console.log('Looks like there was a problem. Status Code: ' +
response.status);
return;
}
return response;
})
.then(response => response.json())
.then(response => {
sessionStorage.setItem(storageKey, JSON.stringify(response))
return response;
})
.catch(function(err) {
console.log('Fetch Error :-S', err);
})
}
var typeaheadElements = [].slice.call(document.getElementsByClassName('typeahead'));
if (typeaheadElements.length) {
console.log('typeaheadfound');
typeaheadElements.map(function(element) {
new Typeahead(element);
});
}
<div class="typeahead">
Typeahead
</div>
<div class="typeahead">
Typeahead
</div>
My "dirty" solution:
Typeahead.js
import fetchPromise from '../utilities/fetchSetStorage.js';
let isFetched = false;
function Typeahead(element) {
init.call(this);
function init() {
var input = element.getElementsByTagName('input')[0];
if (input && !isFetched) {
isFetched = true;
let citiesData = fetchPromise('./cities.json', 'citiesJson');
Promise.all([citiesData]).then(function(values) {
items = values[0];
element.getElementsByTagName('input')[0].removeAttribute('disabled');
});
input.addEventListener('input', handleChange.bind(this));
element.addEventListener('keydown', handleKeyDown.bind(this));
element.addEventListener('click', handleElementClick.bind(this));
document.addEventListener('click', handleDocumentClick.bind(this));
}
}
}

Categories