So I want to return a value from a subscribe function like this:
async obtenerListadoClases(categoria) {
var clasesDB = await this.getClases(categoria)
.subscribe((data: any) => {
clasesDB = data.clasesDB // **Want to return this**
console.log(clasesDB,'clasesDB'); // **Getting Value**
})
console.log(clasesDB, 'outside'); // **Not Getting Value**
return clasesDB;
}
Also, I want to use this function in another place like this:
var listaClases = await this.claseServicio.obtenerListadoClases(categoria); // Not getting the correct info
// console.log(listaClases , 'listado clases');
What Im doing wrong? Or how can I fix it? Thanks in advance!
You can only subscribe to observables.
The Observable way
getClases(categoria): Observable<any> {
return new Observable(observer => {
// logic to return data
observer.next(data);
observer.complete()
// logic when error
observer.error(error);
});
}
Return the getClases() function
obtenerListadoClases(categoria): Observable<any>{
return this.getClases(categoria);
}
Use the function where you want:
this.obtenerListadoClases(categoria)
.subscribe(
result => {
// what you want to do with the result
},
error => {
// what you want to do with the error
});
The Promise way
getClases(categoria): Promise<any> {
return new Promise((resolve, reject) => {
// logic to return data
resolve(data);
// logic when error
reject(error);
});
}
Return the getClases() function
obtenerListadoClases(categoria): Promise<any>{
return this.getClases(categoria);
}
Use the function where you want:
this.obtenerListadoClases(categoria)
.then(result => {
// what you want to do with the result
})
.catch(error => {
// what you want to do with the error
});
You should be using promises with the .subscribe(). Only observables use .subcribe()
Also, stay away from promises in the angular world. Time to think reactive.
Is this returning an observable? this.getClases(categoria) post the code please.
Related
I'm trying to transform a Stream of a list of one type into a Stream of a list of another type, and having an issue with this.
I have this list of Habits that I'm streaming from Firebase, and I want to accept that stream in a function, and return a new stream that is a list of ViewModels of another type from it. But my function is returning a stream of the wrong type.
Here is my code:
Stream<List<HabitCompletionViewModel>> _getTodaysHabits(
Stream<List<Habit>> habitsStream) {
var result = habitsStream.map((habitsList) {
habitsList.map(
(habit) async {
await _getHabitCompletionsCurrent(habit);
HabitCompletion completion = habit.completions!.firstWhere(
(completion) => completion.date
.dayEqualityCheck(DateTime.now().startOfDate()));
return HabitCompletionViewModel(completion: completion, habit: habit);
},
).toList();
});
return result;
}
I am getting a compile error because the result variable is showing as type Stream<Null> when I hover over it, where I would expect it to be Stream<List<HabitCompletionViewModel>>. Any idea what I'm doing wrong?
Your outer .map call does not have a return statement which is why you are getting a Stream<Null>.
So add a return statement like so:
Stream<List<HabitCompletionViewModel>> _getTodaysHabits(
Stream<List<Habit>> habitsStream) {
var result = habitsStream.map((habitsList) {
// added return statement here
return habitsList.map(
(habit) async {
await _getHabitCompletionsCurrent(habit);
HabitCompletion completion = habit.completions!.firstWhere(
(completion) =>
completion.date.dayEqualityCheck(DateTime.now().startOfDate()));
return HabitCompletionViewModel(completion: completion, habit: habit);
},
).toList();
});
return result;
}
However the above code still has an error because it is now returning a Stream<List<Future<HabitCompletionViewModel>>> instead of the desired Stream<List<HabitCompletionViewModel>>. To solve this you can use .asyncMap instead of .map.
Stream<List<HabitCompletionViewModel>> _getTodaysHabits(
Stream<List<Habit>> habitsStream) {
var result = habitsStream.asyncMap((habitsList) {
return Stream.fromIterable(habitsList).asyncMap(
(habit) async {
await _getHabitCompletionsCurrent(habit);
HabitCompletion completion = habit.completions!.firstWhere(
(completion) =>
completion.date.dayEqualityCheck(DateTime.now().startOfDate()));
return HabitCompletionViewModel(completion: completion, habit: habit);
},
).toList();
});
return result;
}
I have a function which does some asynchronous operations and I want to return the status of the operation back to the caller. How can I achieve this?
Future<bool> setData() async {
Firestore.instance.collection("test").document('$id').setData({
'id': 'test'
}).then((onValue) {
print('Data set success');
return true;
}).catchError((onError) {
print('Data set Error!!!');
return false;
});
}
//Calling
final status = await setData();
if(status){
//do success
}
But this function complains that it doesn't end with a return statement. What is the logical mistake I'm making here?
You miss a return in your setData function
return Firestore.instance....
I've tried AsyncStorage, react-native-store, and react-native-simple-store, and they all work in the simulator, but not on a device. I'm using redux and redux-thunk to load the stored state. I call the following function in my root component's componentDidMount method (using react-native-simple-store):
export function loadState() {
return (dispatch, getState) => {
store.get('state').then((state) => {
if (state) {
let action = {
type: LOAD_STATE,
state: fromJS(state),
};
dispatch(action);
} else {
store.save('state', initialState);
}
}).catch((error) => {
console.log(error);
});
};
}
And then in my reducer when the user triggers an update I'll update the state in storage before returning the new state like this:
case SET_UPDATED_DATE:
newState = state.set('updatedDate', action.date);
store.update('state', newState.toJS())
.catch((error) => console.log(error));
return newState;
Is the initializing/updating approach insufficient? Does something special need to be done to set it up for a device? Or is redux-thunk not supported when run on a device – main.jsbundle or with the development server – (putting a log statement at the top of the loadState function's returned function leads me to believe it may not be being called when on a device)?
Following the AsyncStorage docs' example, I've figured out a way to make it work. In my reducer file (my redux state is an Immutable.js object):
var STORAGE_KEY = '#AppName:state';
export function loadState() {
return async (dispatch, getState) => {
try {
var value = await AsyncStorage.getItem(STORAGE_KEY);
if (value !== null) {
dispatch(replaceState(value));
console.log('Recovered selection from disk:');
console.log(value);
} else {
saveState(JSON.stringify(initialState.toJS()));
console.log('No state on disk. Initialized with initialState.');
}
} catch (error) {
console.log('AsyncStorage error: ' + error.message);
}
};
}
function replaceState(newState) {
return {
type: REPLACE_STATE,
newState: fromJS(JSON.parse(newState)),
};
}
async function saveState(state) {
try {
await AsyncStorage.setItem(STORAGE_KEY, state);
console.log('Saved selection to disk:');
console.log(state);
} catch (error) {
console.log('AsyncStorage error: ' + error.message);
}
}
Then in the reducer function:
case SET_UPDATED_DATE:
newState = state.set('updatedDate', action.date);
saveState(JSON.stringify(newState.toJS()));
return newState;
I would like to test a method which execute a POST on another server :
Future executePost() {
_client.post("http://localhost/path", body : '${data}').then((response) {
_logger.info("Response status : ${response.statusCode}");
_logger.info("Response body : ${response.body}");
Completer completer = new Completer();
completer.complete(true);
return completer.future;
}).catchError((error, stackTrace) {
_logger.info(error);
_logger.info(stackTrace);
});
}
The problem I'm dealing with is that my testing method ends before the future returned by "_client.post" is executed.
My testing method :
test('should be true', () {
try {
Future ok = new MyClient().executePost();
expect(ok, completion(equals(true)));
} catch(e, s) {
_logger.severe(e);
_logger.severe(s);
}
});
Thanks for your help !
Your executePost() method doesn't even return a future, it returns null.
client.post() returns a future but this return value isn't used.
Try to change it to:
Future executePost() {
return _client.post("http://localhost/path", body : '${data}').then((response) {
_logger.info("Response status : ${response.statusCode}");
_logger.info("Response body : ${response.body}");
return true;
}).catchError((error, stackTrace) {
_logger.info(error);
_logger.info(stackTrace);
});
}
After many attempts to get the content of the response in HttpRequest, I failed completely to know or understand why I can't have what I want, and I must mention that I can log and manipulate the response only inside an onReadyStateChange (onLoad and onLoadEnd are giving me the same results!), but I really want that value outside the callback.
Here is the part of code that I'm stuck with
Map responsData;
req=new HttpRequest()
..open(method,url)
..send(infojson);
req.onReadyStateChange.listen((ProgressEvent e){
if (req.readyState == HttpRequest.DONE ){
if(req.status == 200){
responsData = {'data': req.responseText};
print("data receaved: ${ req.responseText}");
//will log {"data":mydata}
}
if(req.status == 0){
responsData = {'data':'No server'};
print(responsData );
//will log {"data":No server}
}
}
});
//anything here to get responsData won't work
You have to assign an onLoad callback before you call send.
I'm not sure what you mean with only inside an onReadyStateChange.
Maybe you want to assign the responseText to a variable outside the the callback.
Create a method:
Future<String> send(String method, String url, String infojson) {
var completer = new Completer<String>();
// var result;
req=new HttpRequest()
..open(method,url)
..onLoad.listen((event) {
//print('Request complete ${event.target.reponseText}'))
// result = event.target.responseText;
completer.complete(event.target.responseText);
})
..send(infojson);
return completer.future;
}
and call this method like
var result;
send(method, url).then(
(e) {
// result = e;
print('Request complete ${e}'));
});