Execute method after getting response from $http.get - angularjs

I want to add a profile if it doesn't exist, otherwise, I will only do an update:
profileExists(id) {
return this.$http.get('/profiles/' + id).then(response => {
return response.data;
});
}
submitProfile(profile) {
if (!this.profileExists(profile.id)) {
this.addProfile(profile);
} else {
this.updateProfile(profile);
}
}
addProfile(profile) {
return this.$http.post('/profiles', profile)
.then(res => res.data)
.catch(this.$http.fallback);
}
updateProfile(profile) {
return this.$http.put('/profiles/' + profile.id)
.then(res => res.data)
.catch(this.$http.fallback);
}
The problem with this code is that in the submitProfile method, this.addProfile(profile); is executed before the return statement of profileExists(id)... I have a hard time manipulating asynchronous code. I don't know how to execute the code after finishing all the profileExists(id) method.
And my second question is why do we put a return statement on this.$http.get or this.$http.put?
Thanks.

I think's you need to call your addProfile() in success callback from your profileExists()
Try this.
profileExists(id) {
return this.$http.get('/profiles/' + id).then(response => {
if(!response.data){
this.addProfile(profile);
}else{
this.updateProfile(profile);
}
});
}
Or
profileExists(id){
return this.$http.get('/profiles/' + id);
}
submitProfile(profile) {
this.profileExists(profile.id).then(response => {
if (!response.data) {
this.addProfile(profile);
} else {
this.updateProfile(profile);
}
})
}

By the time your code reaches the if clause, profileExists has not returned, so it evaluates to false. You can change your code to check in the callback function
submitProfile(profile) {
this.profileExists(profile.id)
.then(response => {
if(!response.data){
this.addProfile(profile);
} else {
this.updateProfile(profile);
}
})
}

You can do it this way:
submitProfile(profile) {
return this.profileExists(profile.id)
.then(exists => {
if(!exists){
return this.addProfile(profile);
} else {
return this.updateProfile(profile);
}
})
}
We put return before the actual call because we want to return the promise . So whomever is calling submitProfile can perform some action after this action is performed. Like this :
service.submitProfile(profile)
.then(result => console.log('submit success'));
Also they can catch errors wherever it happened in all the code above in single place.
service.submitProfile(profile)
.then(result => console.log('submit success'))
.catch(err => console.error('Failed to submit',err);

You need to set async http true. Try adding this line of code in your config.
$httpProvider.useApplyAsync(true);

Related

AsyncStorage doesn't save data but no error

Now I am aware that there are many of questions that asked the same thing. But I also found many that implemented the right methods but nothing worked for them even peoples' answers
Basically, I wanted to use AsyncStorage to save a few user preferences. At first everything worked and was saved correctly, but then suddenly nothing worked anymore.
I kept trying and trying, and made a very interesting finding.
First here's my code:
My import:
import AsyncStorage from '#react-native-async-storage/async-storage';
Default State:
state : AppState = {
messages: [],
isMuted: false
}
This is my getter. It works on init:
componentDidMount() {
this.getSettings();
}
async getSettings() {
try {
AsyncStorage.getItem("muted").then((muted)=> {
if (muted != null) {
this.setState({"isMuted": eval(muted)});
console.log("init! "+this.state.isMuted.toString());
} else {
console.log("init! found null");
}
})
} catch(e) {
// error reading value
}
}
Here's my setter, it works onPress of a button
onPressSpeaker = async () => {
var muted = !this.state.isMuted;
this.setState({"isMuted": muted});
try {
await AsyncStorage.setItem("muted", this.state.isMuted.toString());
console.log("saved! "+this.state.isMuted.toString());
const muted = await AsyncStorage.getItem('muted');
if(muted !== null) {
console.log("data found! "+this.state.isMuted.toString());
}
} catch (e) {
console.log("error")
}
};
I believe I set everything correctly.
But here's my log (from Flipper)
20:57:41.654
init! true
20:57:44.247
saved! false
20:57:44.256
data found! false
20:58:04.788
Running "Voice Message" with {"rootTag":51}
20:58:05.800
init! true
The last init was supposed to return the new value but it keeps returning the old value again and again, everytime I refresh (restart) the application.
Did I do something wrong? Am I missing something? Is there something I need to know about react-native-async-storage?
I think the problem that you are storing the this.state.isMuted value before the state mutates
To better understand you can try this code
onPressSpeaker = async () => {
var muted = !this.state.isMuted;
this.setState({"isMuted": muted});
try {
//Here we are trying to log the state before Add it to Storage
console.log('State => Before AsyncStorage.setItem', this.state.isMuted)
await AsyncStorage.setItem("muted", this.state.isMuted.toString());
console.log("saved! "+this.state.isMuted.toString());
const muted = await AsyncStorage.getItem('muted');
if(muted !== null) {
console.log("data found! "+this.state.isMuted.toString());
}
} catch (e) {
console.log("error")
}
};
Your log will now be like this
20:57:41.654
init! true
20:57:44.247
'State => Before AsyncStorage.setItem' true
20:57:44.247
saved! false
20:57:44.256
data found! false
Solution: So you need to write the function in the callback to the setState function
storeIsMuted = async () => {
try {
console.log("before setItem", this.state.isMuted.toString());
await AsyncStorage.setItem("muted", this.state.isMuted.toString());
console.log("saved! " + this.state.isMuted.toString());
//
const muted = await AsyncStorage.getItem("muted");
if (muted !== null) {
console.log("data found! " + this.state.isMuted.toString());
}
} catch (e) {
console.log("error");
}
};
onPressSpeaker = () => {
var muted = !this.state.isMuted
this.setState({ isMuted: muted }, async () => this.storeMuted());
};
Documentation
SetState

react typescript return value with asynchronous functions

I don't understand what's wrong here.
I get the message: TS2366: Function lacks ending return statement and return type does not include 'undefined'.
I have a promise and I give number-type returns everywhere.
Does somebody has any idea?
export async function setAdress(newAdress: IAdress):Promise<number> {
try {
await axios.post<IAddAdressResult>('http://localhost:8090/rest/web/api/addAdress', newAdress)
.then(res=> {
if (res.data && (res.data as IAddAdressResult)) {
alert('Address written successfully. ' + res.data.ADRESSID.toString());
return res.data.ADRESSID
} else return 0
})
.catch(error => {
alert('Error writing the address ' + error);
return 0
});
} catch (e) {
return 0
}
}
You need to return the whole Promise chain. As is, the setAdress function doesn't return anything.
You should also consider fixing the spelling to address (typos are a frequent source of bugs in programming), and the try/catch is superfluous if you also have a .catch.
export async function setAdress(newAdress: IAdress): Promise<number> {
return axios.post<IAddAdressResult>('http://localhost:8090/rest/web/api/addAdress', newAdress)
.then(res => {
if (res.data && (res.data as IAddAdressResult)) {
alert('Address written successfully. ' + res.data.ADRESSID.toString());
return res.data.ADRESSID
} else return 0
})
.catch(error => {
alert('Error writing the address ' + error);
return 0
});
}

how to get the result from recursive promises in a redux action

I've searched the net, and I can't find out a solution. My final goal is to pull all the data from a dynamodb table. The problem is when a table is bigger than 1MB, in the response I'll get one chunk of data and a LastEvaluatedKey parameter (which provides the index I can use in the next call to get the next chunk). The scan operation is documented here if needed.
I'm using reactjs, redux and redux-thunk in my app.
I have used promises moderately in the single or chained formats, but this one is more challenging that I could resolve so far. What puzzles me is the fact that the new calls can not be made without receiving the previous response, so the calls can not be done simultaneously in my opinion. In another hand since the scan operation is a promise (as far as I understand) if I try to return a promise from my own method the action does not receive the results.
I'm very confused and I really like to understand how I can get this to work.
action:
function getDynamodbTableRecords(tableName) {
return dispatch => {
dispatch(request());
var recordsSet = [];
var data = myAwsService.getTableRecords(tableName, null) || {Items:[]};
if (data.Items.length > 0){
data.Items.map(record => {
recordsSet.push(record);
});
dispatch(success(recordsSet));
} else {
dispatch(failure("No Records Found!"));
}
};
function request() { return { type: DATA_LOADING, selectedTable: tableName } }
function success(tableRecords) { return { type: DATA_LOAD_SUCCESS, tableRecords } }
function failure(error) { return { type: DATA_LOAD_FAILED, errors: error } }
}
myAwsService:
function getTableRecords(tableName, lastEvaluatedKey = null) {
getRecordsBatch(tableName, lastEvaluatedKey)
.then(
data => {
if (data.LastEvaluatedKey) {
return getTableRecords(tableName, data.LastEvaluatedKey)
.then(
nextData => {
data.Items = data.Items.concat(nextData.Items);
}
)
}
return data;
}
)
}
function getRecordsBatch(tableName, lastEvaluatedKey = null) {
var awsDynamodb = new DynamoDB();
let params = { TableName: tableName };
if (lastEvaluatedKey) {
params['ExclusiveStartKey'] = lastEvaluatedKey;
}
return new Promise((resolve, reject) => {
awsDynamodb.scan(params, function(err, data) {
if (err) {
reject(err);
}
return resolve(data);
});
});
}
Not sure if your recursive promise is working but I'd do it like this:
function getTableRecords(
tableName,
lastEvaluatedKey = null,
result = { Items: [] }
) {
return getRecordsBatch(tableName, lastEvaluatedKey).then(
data => {
if (data.LastEvaluatedKey) {
return getTableRecords(
tableName,
data.LastEvaluatedKey,
{
...data,
Items: result.Items.concat(data.Items),
}
);
}
return {
...data,
Items: result.Items.concat(data.Items),
};
}
);
}
The action should also dispatch the data.Items and not the promise that getTabelRecords returns and you probably want to dispatch failure action if something goes wrong:
function getDynamodbTableRecords(tableName) {
return async dispatch => {
dispatch(request());
//you probably want the data, not a promise of data
try {
var data = await myAwsService.getTableRecords(
tableName,
null
);
if (data.Items.length > 0) {
//no reason to have the temporary recordSet variable
dispatch(success(data.Items.map(record => record)));
} else {
dispatch(failure('No Records Found!'));
}
} catch (e) {
dispatch(failure(e.message));
}
};
function request() {
return { type: DATA_LOADING, selectedTable: tableName };
}
function success(tableRecords) {
return { type: DATA_LOAD_SUCCESS, tableRecords };
}
function failure(error) {
return { type: DATA_LOAD_FAILED, errors: error };
}
}

React Native function not triggering

So, I have this component,
{ this.props.isConfirmModalOpen && shiftInvite && <ConfirmApplicationPopUp
memberPhoto={props.memberProfile && props.memberProfile.photo}
venueLogo={getOr('noop', 'account.logo', shiftInvite)}
isOpen={props.isConfirmModalOpen}
shift={shiftInvite}
isOnboarding={isOnboardingMember}
onClose={props.onToggleConfirmPopUp}
onConfirm={this.handleConfirmApplication}
checkValues={props.confirmationCheckValues}
onUpdateCheckValues={props.onUpdateConfirmationCheckValues}
isHomeComponent
/> }
As you can see, I pass on onConfirm the handleConfirmApplication function, which is a check for some stuff and has to run a function in the try block, , here's the function
handleConfirmApplication = async () => {
const checkVals =
get('shift.account.accountName', this.props) === ONBOARDING_ACCOUNT
? omit('payRate', this.props.confirmationCheckValues)
: this.props.confirmationCheckValues;
if (Object.values(checkVals).every(val => val)) {
this.props.onToggleConfirmPopUp();
this.props.onToggleLoadingApply();
try {
console.log('inTry1');
await this.handleShiftInviteDecision('ACCEPT');
console.log('inTry2');
} catch (e) {
Alert.alert('Error', parseError(e));
} finally {
this.props.onToggleLoadingApply();
console.log('inFinally');
}
} else {
Alert.alert('Error', 'Please confirm all shift requirements');
}
};
My problem is, for whatever reason, it doesn't run the handleShiftInviteDecision('ACCEPT) for whatever reason, i'm awaiting it, tried to put it in another function, call them both from another function ETC, the function does not run!
Here's the handleShiftInviteDecision function too
handleShiftInviteDecision = (decision: 'ACCEPT' | 'DECLINE') => async () => {
console.log('handleSIDecision1');
const [shiftInvite] = getOr([], 'shiftInvites', this.state.modals);
console.log('handleSIDecision2');
if (decision === 'ACCEPT') {
analytics.hit(new PageHit(`ShiftInviteModal-ACCEPT-${shiftInvite.id}`));
console.log('handleSIDecision3');
} else if (decision === 'DECLINE') {
analytics.hit(new PageHit(`ShiftInviteModal-DECLINE-${shiftInvite.id}`));
console.log('handleSIDecision4');
}
try {
console.log("thisSHouldRun")
this.setState({ isLoading: true, display: false });
await this.props.updateMyApplication(shiftInvite.id, decision);
console.log('handleSIDecision5');
} catch (e) {
Alert.alert('Error', parseError(e));
} finally {
this.setState({ isLoading: false, display: false });
}
};
Any ideeas on what I could do?
The function handleShiftInviteDecision is a function that returns an async function.
handleShiftInviteDecision = (decision: 'ACCEPT' | 'DECLINE') => async () => {
So, you would need to call the async function it returns to invoke it:
try {
console.log('inTry1');
await this.handleShiftInviteDecision('ACCEPT')(); // <--- here
console.log('inTry2');
} catch (e) {

Return observable from nested observable

I am trying to return a boolean observable from a response that I get from an observable that is inside a response from a parent observable. But the child observable will not always run depending on the res from the parent observable.
I know to make this work I have to use .map and I can return the observable in the subscribe but after that I am stumped.
the scenario is that I do an auth check if that passes then do the api call if it fails return false. If the api call fails return false and if it succeeds return true.
getEvents(): Observable<boolean> {
this.authSrvc.authCheck().map((res: boolean) => {
if (res) {
this.eventsSrvc.getEvents(this.pageNum, this.pageSize, this.searchText).timeout(15000).map((data: Response) => data.json()).subscribe((res:any)=>
{
if(res.value.length === 0)
{
Observable.of(false);
}
else
{
this.eventsList = this.eventsList.concat(data);
this.storage.ready().then(() => {
this.storage.set('events', this.eventsList)
})
Observable.of(true);
}
},(err:any)=>
{
this.helperSrvc.errorMessage(err);
return Observable.of(false);
})
}
else {
this.helperSrvc.authFailed();
this.authSrvc.logout();
this.pushSrvc.unRegisterPush();
this.calendarSrvc.clearEvents();
this.locationSrvc.clearGeofences();
this.navCtrl.setRoot(AuthPage);
return Observable.of(false);
//
}
})
}
I either cant get the response or I get told that the function that calls this doesnt have .subscribe() available.
I think you need to use flatMap, I have changed your code below.
getEvents(): Observable<boolean> {
return this.authSrvc.authCheck().flatMap((res: boolean) => {
if (res) {
return this.eventsSrvc.getEvents(this.pageNum, this.pageSize, this.searchText)
.timeout(15000)
.map((data: Response) => data.json())
.flatMap((res: any) => {
if (res.value.length === 0) {
return Observable.of(false);
}
else {
this.eventsList = this.eventsList.concat(data);
this.storage.ready().then(() => {
this.storage.set('events', this.eventsList);
});
return Observable.of(true);
}
});
}
else {
return Observable.of(false);
//
}
})
}
EDIT: I removed your error handler, you need to pass it when you subscribe to getEvents.
getEvents().subscribe(
(res:boolen) => {},
(err:any)=>{
this.helperSrvc.errorMessage(err);
}
);

Resources