I am very new to Flutter, and stuck at the following problem:
child: RaisedButton(
onPressed: () {
fetchData();
},
// ...
fetchData() async {
final res = await http.get("https://jsonplaceholder.typicode.com/posts");
if (res.statusCode == 200) {
// If the call to the server was successful, parse the JSON
print("it works");
return json.decode(res.body);
} else {
// If that call was not successful, throw an error.
throw Exception('Failed to load post');
}
}
// ...
when i remove the http.get part it prints "it works" so i think the problem is in the http.get executing.
Make the onPressed async and add an await to fetchData().
Make your method of type Future, and let it return the data type dynamic like this. And then call it wherever you want.
Future<dynamic> fetchData() async {
final res = await http.get("https://jsonplaceholder.typicode.com/posts");
if (res.statusCode == 200) {
// If the call to the server was successful, parse the JSON
print("it works");
return json.decode(res.body);
} else {
// If that call was not successful, throw an error.
throw Exception('Failed to load post');
}
}
And call it via this, since you are returning the data
child: RaisedButton(
onPressed: () {
// the value is the call back function data which you're returning
fetchData().then((value){
// since the data it return is a dynamic one
print(value.toString());
});
}
)
If you don't want to return any data, and just simply call the method. Then do this
fetchData() async {
final res = await http.get("https://jsonplaceholder.typicode.com/posts");
if (res.statusCode == 200) {
// If the call to the server was successful, parse the JSON
print("it works");
// do not return
print(json.decode(res.body).toString());
} else {
// If that call was not successful, throw an error.
throw Exception('Failed to load post');
}
}
And simply call like your method call in your code
child: RaisedButton(
// no need of anything now
onPressed: () => fetchData()
)
Solved by running Flutter clean still don't know how
Related
I have an existing async function:
async doJSONGetRequest(getUrl, accessToken) {
return new Promise(function(resolve, reject) {
const reqHeaders = {
'Content-Type': 'application/json',
'Authorization': `Bearer ${accessToken}`,
};
console.info('url = ' + getUrl);
request.get({
url: getUrl,
headers: reqHeaders,
}, function(err, response) {
if (err) return reject(err);
try {
// console.debug(`response = ${response.body}`);
const parsed = JSON.parse(response.body);
return resolve(parsed);
} catch (err) {
return reject(err);
}
});
});
}
}
I'm trying to test it with Jasmine(v4).
Of course, I don't want this thing to actually make an HTTP request, so I tried rigging up a spy on the 'request' package's 'get' function in the 'beforeAll' section:
describe('RAPIDAPIService', function() {
beforeAll(async function() {
spyOn(request, 'get')
.and
.callFake(async (parameters) => {
if (parameters.url === 'http://localhost/api/getSomething') {
const rsp = {};
rsp.body = 'good stuff';
return rsp;
} else if (parameters.url === 'http://localhost/api/whoops') {
return new Error('401 not found');
} else {
return null;
}
});
});
it('doJSONGetRequest should run successfully', async () => {
expect(api.doJSONGetRequest).toBeDefined();
const res = await api.doJSONGetRequest('http://localhost/api/getSomething', '12345678');
expect(data).toEqual('good stuff');
});
it('doJSONGetRequest should resolve errors properly', async () => {
expect(api.doJSONGetRequest).toBeDefined();
const res = await api.doJSONGetRequest('http://localhost/api/whoops', '12345678');
const expectedError = new Error('401 not found');
expect(res).toEqual(expectedError);
});
Console log statements seem to indicate that I'm actually getting past / returning something from my "await" calls in the "it" tests. But the spies are actually working / detecting that the url's have been called.
(Note that I'm not including here other tests in the same file that do not make asynchronous calls and ARE working... just so you know that there's no problem accessing the actual "api" library and its functions.)
These two tests keep failing with "Error: Timeout - Async function did not complete within 5000ms". And like I said, it seems like they're not returning back to the tests from their calls to the doJSONGetRequest function.
Any thoughts?
Thanks!
I am thinking the issue is the mocking. request.get seems to take two parameters and I am thinking you need to call the 2nd parameter (callback function) once you are done so the resolve can be called.
Try this:
spyOn(request, 'get')
.and
// add callbackFunction as 2nd argument
.callFake((parameters, callbackFunction) => {
if (parameters.url === 'http://localhost/api/getSomething') {
const rsp = {};
rsp.body = 'good stuff';
callbackFunction(null, rsp);
} else if (parameters.url === 'http://localhost/api/whoops') {
callbackFunction({ error: '401 not found' }, {});
} else {
callbackFunction(null, null);
}
});
Good day, I am receiving the following error when running code for my application:
The method 'onLogin' was called on null
( 6100): Receiver: null
( 6100): Tried calling: onLogin("Succeed")
I was trying to neaten my code by putting my analytics stuff within a different file, but doing so has brought up this error and it now no longer sends a "login" event to Firebase. I'm very curious to know why I can not use this method to achieve the same goal. Code:
login-page.dart
Widget _signInButton() {
return OutlineButton(
splashColor: Colors.grey,
onPressed: () async {
FireBaseAnalyticsData user;
String result = await signInWithGoogle();
if (result == "Succeed") {
Navigator.pushNamed(context, '/specials-page'); //'specials' = tab-creation page
user.onLogin(result); //track login
}
else
print("error logging in");
},
... //other code
firebase-analytics.dart
final FirebaseAnalytics analytics = FirebaseAnalytics();
class FireBaseAnalyticsData {
void onLogin(var x) {
if(x == "Succeed")
{
analytics.logLogin();
print("Log in successful");
}
else
print("Error delivering login stats");
}
}
I am not getting any syntax errors with my implementation, but I seem to be missing something with regards to the logic of this. Any and all help would be appreciated. Thank you.
You only declared user variable. you have to initialize it before using it inuser.onLogin(result)
Widget _signInButton() {
return OutlineButton(
splashColor: Colors.grey,
onPressed: () async {
final user = FireBaseAnalyticsData(); //TODO: Initialize user here
String result = await signInWithGoogle();
if (result == "Succeed") {
Navigator.pushNamed(context, '/specials-page'); //'specials' = tab-creation page
user.onLogin(result); //track login
}
else
print("error logging in");
},
You have just created a user variable of type FireBaseAnalyticsData, but have not initialized it. You need to initialize the user variable for user.onLogin(result) to function properly. Just initialize it as shown below and everything should work fine. 👍🏼
FireBaseAnalyticsData user = FireBaseAnalyticsData();
I have a cloud code from which I call an external function.
The cloud code response is null but the console displays the response
my cloud code ;
Parse.Cloud.define("testccadd", async request => {
try {
var ccaddrequest = {
conversationId: '123456789',
email: 'email#email.com',
};
externalFunction (ccaddrequest, function (err, result) {
console.log(result);
return result;
}) ;
} catch (e) {
console.log("Error");
}
});
console.log (result); shows the values from the external function, but the return result; returns null
how can I get the external function response as response of my cloud code function ?
The problem is that your externalFunction uses a callback to return its result. That is an asynchronous event, meaning that it happens after your cloud functions has been processed.
The cloud function will execute var ccaddrequest... and then call externalFunction but it won't "wait" for externalFunction to call the callback function if it contains asynchronous commands.
So you need to wrap the externalFunction in a Promise (see how to promisify callbacks) and then await the result of it.
Plus you need to return the result of the Promise, so in your code you need to add
Parse.Cloud.define("testccadd", async request => {
try {
var ccaddrequest = {
conversationId: '123456789',
email: 'email#email.com',
};
var result = await externalFunctionPromise(...);
return result;
} catch (e) {
console.log("Error");
}
});
I need to make a function call which does not return anything (void). Only way to get notified about function completion is sending a callback function.
Now I an using BLoC pattern along with ReDux, When an event is dispatched, I dispatch another action to store of redux, After action is completed it calls the callback function. And now inside callback function, I want to update the state of bloc. Below is my implementation,
if (event is Login) {
yield currentState.copyWith(formProcessing: true);
store.dispatch(authActions.login(
currentState.username,
currentState.password,
(error, data) {
print(error);
print(data);
// I want to yield here.
yield currentState.copyWith(formProcessing: false);
},
));
}
As shown in the above code snippet, Inside the callback function, I want to yield.
Solution
Create a function that returns the future and makes callback function to store dispatch, Heres sample.
if (event is Login) {
yield currentState.copyWith(formProcessing: true);
try {
dynamic result = await loginAction(store, currentState.username, currentState.password);
print(result);
yield currentState.copyWith(formProcessing: false);
} catch (e) {
print(e);
}
}
Future loginAction(store, username, password) {
var completer = new Completer();
store.dispatch(authActions.login(
username,
password,
(error, data) {
if (error != null) {
completer.completeError(error);
} else if (data != null) {
completer.complete(data);
}
},
));
return completer.future;
}
You need to create other event, and dispatch this event in your callback function, then you can do what you want in the function that filter your events.
I don't know what is the purpose of your BLoC, but the name of this event depends on the use case, it can be UpdateForm, UpdateState, LoggedIn,LoggedOut, etc. You will find the most descriptive name for your use case.
Remember that you can also create this event with parameters, for example UpdateForm (bool isLoggedIn), and yield different states according to your conditions.
For the example, the name of this event is OtherEvent.
if (event is Login) {
yield currentState.copyWith(formProcessing: true);
store.dispatch(authActions.login(
currentState.username,
currentState.password,
(error, data) {
print(error);
print(data);
dispatch(OtherEvent());
},
));
} else if (event is OtherEvent) {
// You can yield here what you want
yield currentState.copyWith(formProcessing: false);
}
I make a function call to my database, which updates a local object after getting data and takes a few moments.
Because of the Async task, the program moves to the next line of code. unfortunately I need the local object that gets updated with the async call for the next line of code.
how can I wait for my async task to finish before the next piece of code is executed? thank you
edit: adding code to explain
updateUser() {
return FutureBuilder(
future: updateUserData(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState != ConnectionState.done) {
return Text("hello not");
} else {
return Text('Hello!');
}
},
);}
#override
Widget build(BuildContext context) {
switch (_authStatus) {
case AuthStatus.notSignedIn:
return new LoginPage(
auth: auth,
CurrentUser: CurrentUser,
onSignedIn: _signedIn,
);
case AuthStatus.signedIn:
{
updateUser(); //THIS TAKES A COUPLE SECONDS TO FINISH BUT I NEED TO SEND IT TO THE NEXT PAGE
return new HomePage(
auth: auth,
CurrentUser: CurrentUser,
onSignedOut: _signedOut,
);
}
}
}
}
You can use await keyword in async function.
eg:
void someFunc() async {
await someFutureFunction();
// Your block of code
}
Here your block of code wont run until someFutureFunction returns something.
You can also use with custom async function like below example:
(() async {
await restApis.getSearchedProducts(widget.sub_cats_id,widget.keyword).then((val) => setState(()
{
setState(() {
data = val["data"];
});
}));
})();
This might help, The below sample code has two functions,
Below function is used to load the assets and return the JSON content.
Future<String> _loadCountriesAsset() async {
return await rootBundle.loadString('assets/country_codes.json');
}
the other function will use the JSON content and convert the format to model and return to the class.
Future<List<CountryCode>> loadCountryCodes() async {
String jsonString = await _loadCountriesAsset();
final jsonResponse = json.decode(jsonString);
// print(jsonResponse);
CountriesCodeList countriesCodeList =
new CountriesCodeList.fromJson(jsonResponse);
// print("length " + countriesCodeList.codes.length.toString());
return countriesCodeList.codes;
}
Usage in the class, defined a method to call the loadCountryCodes() function from services.dart file.
Future getCountryCodes() async {
var countryCodesList = await loadCountryCodes();
print("**** length " + countryCodesList.length.toString());
// Perform the operations, or update to the UI or server. It should be same for API call as well.
}
Hope this helps.