I'm having this super annoying issue of being unable to grab and display a table from my server hosted on PhpmyAdmin. (I've managed to grab the data and have it printed in the console, but now that I'm trying to display it in a table I can't seem to get it working)
I've tried nulling my variables but I'm not really sure what the main culprit for this error is. Any help would be greatly appreciated.
Image of Error
data.dart File
class dataListing extends StatefulWidget {
const dataListing({Key? key}) : super(key: key);
#override
State<dataListing> createState() => _dataListingState();
}
class _dataListingState extends State<dataListing> {
#override
Widget build(BuildContext context) {
return Container();
}
}
class listingData{
String? ListingID, listingName, listingDescription, address, suburbName, phoneNumber, openingHours, Email, Website;
listingData({
this.ListingID,
this.listingName,
this.listingDescription,
this.address,
this.suburbName,
this.phoneNumber,
this.openingHours,
this.Email,
this.Website,
});
//constructor
List<listingData> datalist = [];
factory listingData.fromJSON(Map<String, dynamic> json){
return listingData(
ListingID: json["ListingID"],
listingName: json["listingName"],
listingDescription: json["listingDescription"],
address: json["address"],
suburbName: json["suburbName"],
phoneNumber: json["phoneNumber"],
openingHours: json["openingHours"],
Email: json["Email"],
Website: json["Website"],
);
}
}
Directory.dart file
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:app/pages/data.dart';
class directoryPage extends StatefulWidget {
#override
State<directoryPage> createState() => _directoryPageState();
}
class _directoryPageState extends State<directoryPage> {
// List serviceListing = [];
//
// getAllListing()async{
// String url = "URL HERE";
// var response = await http.get(Uri.parse(url));
// if (response.statusCode == 200){
// setState (() {
// serviceListing = json.decode(response.body);
// });
// print (serviceListing);
// return serviceListing;
// }
// }
bool error = false, dataloaded = false;
var data;
String dataurl = "URL HERE";
#override
void initState (){
loaddata();
super.initState();
// getAllListing();
}
void loaddata() {
Future.delayed(Duration.zero,() async {
var res = await http.post(Uri.parse(dataurl));
if (res.statusCode == 200) {
setState(() {
data = json.decode(res.body);
dataloaded = true;
});
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Directory'),
centerTitle: true,
elevation: 0,
backgroundColor: Color(0xFFA30B32),
//WSU Appbar Icon
leading: Padding(
padding: const EdgeInsets.all(8.0),
child: Image.asset("assets/wsulogo.png", scale: 8.0),
),
),
body: Container(
padding: EdgeInsets.all(15),
child:dataloaded?datalist():
Center(
child:CircularProgressIndicator()
),
)
);
}
Widget datalist(){
if(data["error"]) {
return Text(data["errmsg"]);
}else{
List<listingData> datalist = List<listingData>.from(data["data"].map((i){
return listingData.fromJSON(i);
})
);
return Table( //if data is loaded then show table
border: TableBorder.all(width:1, color:Colors.black45),
children: datalist.map((listingdata){
return TableRow( //return table row in every loop
children: [
//table cells inside table row
TableCell(child: Padding(
padding: EdgeInsets.all(5),
child:Text(listingdata.ListingID!)
)
),
TableCell(child: Padding(
padding: EdgeInsets.all(5),
child:Text(listingdata.listingName!)
)
),
TableCell(child: Padding(
padding: EdgeInsets.all(5),
child:Text(listingdata.listingDescription!)
)
),
TableCell(child: Padding(
padding: EdgeInsets.all(5),
child:Text(listingdata.address!)
)
),
]
);
}).toList(),
);
}
}
}
Looks like the issue was actually unrelated to the dart side of things, the php code wasn't properly structuring the data. Cannot have underscores or spaces.
Correct-> $json["dballlisting"] = array (); (I renamed it to just "data" later)
Incorrect->$json["db_all_listing"] = array ();
The error seems to be originating from this line, the data['data'] is null which is expected to be an Array.
List<listingData> datalist = List<listingData>.from(data["data"].map((i){
return listingData.fromJSON(i);
})
You need to investigate your API call to make sure why it is happening. If the null value is expected then you need to add safeguards in your code to make sure it won't break when it encounter such scenarios. You can add null safety checks for that one way to do it would be to
List<listingData> datalist = List<listingData>.from((data["data"] ?? []).map((i){
return listingData.fromJSON(i);
})
Related
Hi guys I'm new to flutter . I was working with a follow along tutorial
and this were working out fine until I ran my code and got a null check operator used on a null value and when I remove the ! the code just stays on a loading mode and doesn't return the response from thee api?
please advice
below is my main.dart
import 'package:flutter/material.dart';
import 'package:c3mobiredo/presentation/LoginScreen.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Material App',
home: Home(),
);
}
}
below is my LoginScreen.dart file
import 'package:flutter/material.dart';
import 'package:c3mobiredo/connectivity/apiConfig.dart';
import 'package:c3mobiredo/connectivity/models/getTimesheetForUserDay.dart';
import '../connectivity/Services/api_service.dart';
class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
late List<UserProjectSpecificDay>? _userModel = [];
#override
void initState() {
super.initState();
_getData();
}
void _getData() async {
_userModel = (await ApiService().GetUserProjectSpecificDay())!;//where I'm getting the error but when I remove the ! the code stays in a loading state which is another issue
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('REST API Example'),
),
body: _userModel == null || _userModel!.isEmpty
? const Center(
child: CircularProgressIndicator(),
)
: ListView.builder(
itemCount: _userModel!.length,
itemBuilder: (context, index) {
return Card(
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(_userModel![index].id.toString()),
Text(_userModel![index].project.projectName),
],
),
const SizedBox(
height: 20.0,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(_userModel![index].hours),
Text(_userModel![index].desc),
],
),
],
),
);
},
),
);
}
}
since someone downvote, i update with reference from official documentation:
https://dart.dev/null-safety/understanding-null-safety
https://stackoverflow.com/a/69313493/12838877
when I remove the ! the code just stays on a loading mode
yes it because your _userModel == null
and here you set the condition like that
_userModel == null || _userModel!.isEmpty
? const Center(
child: CircularProgressIndicator(),)
here need to fix
use late means, the value is non-null variable and you will set the value later. remove late when you initilize nullable value.
when you use ? sign, it means, the variable is nullable
List<UserProjectSpecificDay>? _userModel; // since its nullable, no need to set initial value
then on API call:
void _getData() async {
_userModel = await ApiService().GetUserProjectSpecificDay());
}
no need ! anymore, because we had remove late above
last in your body:
body: _userModel == null // only check if null
? const Center(
child: CircularProgressIndicator(),)
: ListView.builder(
itemCount: _userModel.length ?? 0 // if null, set the list length = 0
It means your reponse.body is null. You cn use use a FutureBuiler to build your widget and you can also set a timeout for the request after what you show the user that there is no data.
Eg:
List<UserProjectSpecificDay>? _userModel;
bool isTimeout = false;
String errorMsg = '';
void _getData() async {
ApiService().GetUserProjectSpecificDay().then((response) {
// I suppose you have a "fromMap" in your model
if (response.statusCode == 200) {
var data = jsonDecode(response.body);
_userModel = UserProjectSpecificDay.fromMap(data);
} else if (response.statusCode == 408) {
setState(() {
isTimeout = true;
errorMsg = 'There was a network error';
});
} else setState(() => errorMsg = 'An error occured');
});
}
/* ... */
body: FutureBuilder(
builder: (_, __) {
if (_userModel != null) {
// return your widget
}
if (isTimeout) {
return Center(child: Text(errorMsg);
}
return Center(child: CircularProgressIndicator());
}
I want to fetch all the infinite list view data in parts, means Initially it load 10 data item and on scroll more it should fetch next 10 items.
I am fetching data from my Laravel api and in my Laravel api endpoint there is not option for per_page, so Please help me to integrate load more option of list view data.
Here is my List data.
List<Category> _categoryList = List<Category>();
CategoryService _categoryService = CategoryService();
bool isLoading = true;
#override
void initState() {
super.initState();
_getAllCategories();
}
_getAllCategories() async {
var categories = await _categoryService.getCategories();
var result = json.decode(categories.body);
result['data'].forEach((data) {
var model = Category();
model.id = data["id"];
model.name = data["categoryName"];
model.icon = data["categoryIcon"];
setState(() {
_categoryList.add(model);
isLoading = false;
});
});
}
And I am fetching all data in simple ListTile.
child: ListView.builder(
itemCount: //_categoryList.length,
itemBuilder: (context, index) {
return ListTile(
title: _categoryList.name
);
},
),
So I have a trick and I am using it in my project. What we need here is to load more data when we are at the end of the list. So to do that we can use the ListView.builder() only:
child: ListView.builder(
itemCount: _categoryList.length + 1,
itemBuilder: (context, index) {
if(index == _categoryList.length){
// loadMore();
// return Loading();
}
return ListTile(
title: _categoryList.name
);
}),
So what we are doing is that we have set _categoryList.length + 1 to the itemCount. If _categoryList.length was 10 then we will have 11 items in the ListView and the index range will be 0 - 10. So inside the builder, we are checking that the index is equals to _categoryList.length which is 10. If the index is equals to the length of _categoryList.length, then we are at the end of the List and we can simply call some functions to load more data from Api or to show a loading widget.
I guess I got your question right, in this way you can simply lazy load data when user gets to the end of the List without using any third party libraries.
This process called pagination. Laravel provides a function for it check Pagination in Laravel
For example
$users = DB::table('users')->paginate(15);// 15 is limit per page
And check it too Paging lib in flutter dev.
I have created a sample to load more data using web service
You can see this example and you can implement for you json data.
https://android-pratap.blogspot.com/2018/12/flutter-infinite-listview-using.html
import 'package:akeepo/randomuser_infinitelist.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: InfiniteUsersList(),
);
}
}
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class InfiniteUsersList extends StatefulWidget {
static String tag = 'users-page';
#override
State<StatefulWidget> createState() {
return new _InfiniteUsersListState();
}
}
class _InfiniteUsersListState extends State<InfiniteUsersList> {
List<User> users = new List<User>();
ScrollController _scrollController = new ScrollController();
bool isPerformingRequest = false;
int pageNumber = 0;
#override
void initState() {
super.initState();
// Loading initial data or first request to get the data
_getMoreData();
// Loading data after scroll reaches end of the list
_scrollController.addListener(() {
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
_getMoreData();
}
});
}
// to show progressbar while loading data in background
Widget _buildProgressIndicator() {
return new Padding(
padding: const EdgeInsets.all(8.0),
child: new Center(
child: new Opacity(
opacity: isPerformingRequest ? 1.0 : 0.0,
child: new CircularProgressIndicator(),
),
),
);
}
#override
void dispose() {
_scrollController.dispose();
super.dispose();
}
// Webservice request to load 20 users data using paging
Future<List<User>> _getUsers() async {
List<User> users = new List<User>();
setState(() {
pageNumber++;
});
String url =
"https://api.randomuser.me/?page=$pageNumber&results=20&seed=abc";
print(url);
var response = await http.get(url);
var jsonData = json.decode(response.body);
print(jsonData);
var usersData = jsonData["results"];
for (var user in usersData) {
User newUser = User(user["name"]["first"] + user["name"]["last"],
user["email"], user["picture"]["large"], user["phone"]);
users.add(newUser);
}
return users;
}
_getMoreData() async {
if (!isPerformingRequest) {
setState(() {
isPerformingRequest = true;
});
List<User> newEntries = await _getUsers(); //returns empty list
if (newEntries.isEmpty) {
double edge = 50.0;
double offsetFromBottom = _scrollController.position.maxScrollExtent -
_scrollController.position.pixels;
if (offsetFromBottom < edge) {
_scrollController.animateTo(
_scrollController.offset - (edge - offsetFromBottom),
duration: new Duration(milliseconds: 500),
curve: Curves.easeOut);
}
}
setState(() {
users.addAll(newEntries);
isPerformingRequest = false;
});
}
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Users',
style:
TextStyle(color: Colors.white, fontWeight: FontWeight.bold))),
body: Container(
child: ListView.builder(
shrinkWrap: true,
controller: _scrollController,
itemCount: users.length + 1,
itemBuilder: (BuildContext context, int index) {
if (index == users.length) {
return _buildProgressIndicator();
} else {
return ListTile(
onTap: () {
Navigator.push(
context,
new MaterialPageRoute(
builder: (context) =>
UserDetailPage(users[index])));
},
title: Text(users[index].fullName),
subtitle: Text(users[index].mobileNumber),
leading: CircleAvatar(
backgroundImage: NetworkImage(users[index].imageUrl)),
);
}
})),
);
}
}
class User {
final String fullName;
final String email;
final String imageUrl;
final String mobileNumber;
User(this.fullName, this.email, this.imageUrl, this.mobileNumber);
}
// User Detail Page
class UserDetailPage extends StatelessWidget {
final User user;
UserDetailPage(this.user);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("User Details"),
),
body: Center(
child: Text(
user.fullName,
style: TextStyle(fontSize: 35.0),
),
),
);
}
}
In my Flutter application I am using Provider version 4.0.4 to manage the state of my app. In basic terms, my app will list down the nearby companies with their rating. users can select a organisation, open it and add their rating as well, so the final rating will be updated. I am using the Consumer concept in Provider to handle the tasks.
In NearByPlacesPage class I am listing down the companies around me with rating information. User can click on a company and they will be taken to OrganizationPage page.
In OrganizationPage class, the rating is displayed again. user can add their rating to the system. Then the rating information in both OrganizationPage page and NearByPlacesPage (back page) need to be updated.
The issue is, when the user update the rating, the rating in OrganizationPage get updated but not NearByPlacesPage in back stack. When we go back to NearByPlacesPage, we can clearly see the old rating values. The page need to be reloaded to get updated values.
Below are the important sections in my code
NearByPlacesPage
class NearByPlacesPage extends StatelessWidget {
int orgTypeID;
String orgTypeName;
NearByPlacesPage(this.orgTypeID, this.orgTypeName);
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) => RatingService()),
],
child: SingleChildScrollView(
child: _NearByPlacesPageUI(orgTypeID, orgTypeName),
),
),
appBar: AppBar(
title: Text(orgTypeName),
),
);
}
}
class _NearByPlacesPageUI extends StatefulWidget {
int orgTypeID;
String orgTypename;
_NearByPlacesPageUI(this.orgTypeID, this.orgTypename);
#override
State<StatefulWidget> createState() {
return _NearByPlacesPageState();
}
}
class _NearByPlacesPageState extends State<_NearByPlacesPageUI> {
#override
Widget build(BuildContext context) {
Consumer<RatingService>(builder: (context, data, child){
return Flexible(
child: ListView.builder(
itemCount: orgList.length,
itemBuilder:(BuildContext context, int index) {
Organization organization = orgList[index];
if (organization.isDisabled != true) {
RatingValue ratingValue = data.getData();
return Container(
margin: EdgeInsets.only(
top: 5, left: 5, right: 5),
child: _buildPlace(organization, ratingValue));
} else {
return Container();
}
},),
);
},);
}
}
OrganizationPage
class OrganizationPage extends StatelessWidget {
Organization organization;
String orgTypeName;
OrganizationPage(this.organization, this.orgTypeName);
#override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: _OrganizationPageUI(organization, orgTypeName),
),
backgroundColor: Colors.white,
appBar: AppBar(
title: Text(organization.name),
),
);
}
}
class _OrganizationPageUI extends StatefulWidget {
Organization organization;
String orgTypeName;
_OrganizationPageUI(this.organization, this.orgTypeName);
#override
State<StatefulWidget> createState() {
return _OrganizationPageState();
}
}
class _OrganizationPageState extends State<_OrganizationPageUI> {
#override
Widget build(BuildContext context) {
Consumer<RatingService>(
builder: (context, data, child) {
Consumer<RatingService>(
return Row(
children: <Widget>[
Container(
margin: EdgeInsets.only(top: 10, left: 10),
child: Text(daa.getData()
style: Theme.of(context).textTheme.bodyText2.apply(color: Colors.grey),
),
),
],
);
),
}
}
}
In OrganizationPage there is a AlerDialog, which allows the user to rate and save. When saved, it will call another method which will reload the data.
Widget _ratingDialog(double _rating) {
RatingService _ratingService =
Provider.of<RatingService>(context, listen: false);
Rating _rating = _ratingService.returnRating();
double _ratingValue = _ratingService.returnRating().rating;
return AlertDialog(
title: const Text("Your Rating"),
actions: [
new FlatButton(
child: const Text("Save"),
//onPressed: () => Navigator.pop(context),
onPressed: () async {
Rating rating = Rating(
idrating:
_rating.idrating != null ? _rating.idrating : null,
user: _user,
organization: widget.organization,
rating: _ratingValue,
dateCreated: DateTime.now().millisecondsSinceEpoch,
lastUpdated: DateTime.now().millisecondsSinceEpoch);
await _ratingService.saveOrUpdateRating(rating, authToken);
_loadRatingByUserAndOrganization(authToken);
_loadRatingValueByOrganization(authToken);
Navigator.pop(context);
},
),
],
);
}
Future _loadRatingByUserAndOrganization(String authToken) {
RatingService _ratingService =Provider.of<RatingService>(context, listen: false);
return _ratingService.getRatingByUserAndOrganization(
_authService.getDatabaseUser().user.iduser,
widget.organization.idorganization,
authToken);
}
RatingService
This is the class which is responsible for calling notifyListeners(). It will be triggered by the above AlertDialog and the expected behaviour is to reload data in both OrganizationPage and NearByPlacesPage
class RatingService with ChangeNotifier {
List<RatingValue> _ratingValueList ;
List<RatingValue> getData()
{
return _ratingValueList;
}
//Load rating by user and Organization
Future<void> getRatingByUserAndOrganization(int idUser, int organizationID, String authToken) async {
try {
var data = await http.get(
_navLinks.getRatingByUserAndOrganization(idUser, organizationID),
headers: {HttpHeaders.authorizationHeader: "Bearer $authToken"},
);
print(data.body);
_rating = Rating.fromJson(convert.json.decode(data.body));
notifyListeners();
} catch (error) {
print(error);
throw error;
}
}
}
What I have I done wrong?
I have written the following code below in Flutter
import 'dart:ui';
import 'package:flutter/material.dart';
import 'dart:io';
import 'package:geolocator/geolocator.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
void main() => runApp(Myapp());
class Myapp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Hello World'),
centerTitle: true,
backgroundColor: Colors.blueAccent,
),
body: Center(child: MyStatefulWidget(),
),
)
);
}
}
class Weather extends StatefulWidget {
UpdateTextState createState() => UpdateTextState();
}
class UpdateTextState extends State {
// var textHolder = 'Getting';
weath() async {
Position position = await Geolocator().getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
print(position.latitude);
print(position.longitude);
var url = 'https://api.openweathermap.org/data/2.5/weather?lat=${position.latitude}&lon=${position.longitude}&appid=myapiid';
print(url);
var response = await http.get(url);
var dart = json.decode(response.body);
var dartt = dart['main'];
var climate = dartt['temp'];
var weather = climate - 32 * 5/9;
// print('Response status: ${response.statusCode}');
// print('Response body: ${json.decode(response.body)}');
// print(dart['main']);
// print(dartt['temp']);
var textHolder = '${weather.toString()}C';
return textHolder;
}
#override
Widget build(BuildContext context) {
var c = weath();
//print(textHolder);
//changeText();
return Scaffold(
body: Center(child: Column(
children: <Widget>[
Container(
padding: EdgeInsets.fromLTRB(20, 20, 20, 20),
child: Text(c),
),
]))
);
}
}
if I run this program this is the output I am getting Please refer to This image actually I want the weather that I get from the API which is text holder variable please Help me guys I have even tried without return statement too also I have tried adding the function directly which also didn't work out well basically is there any alternate way or did I make any mistake in the code
It's a Future so you can call it in your initState and use setState to update the c variable. or you can use FutureBuilder.
class Weather extends StatefulWidget {
UpdateTextState createState() => UpdateTextState();
}
class UpdateTextState extends State {
var c = 'Getting';
weath() async {
Position position = await Geolocator().getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
print(position.latitude);
print(position.longitude);
var url = 'https://api.openweathermap.org/data/2.5/weather?lat=${position.latitude}&lon=${position.longitude}&appid=myapiid';
print(url);
var response = await http.get(url);
var dart = json.decode(response.body);
var dartt = dart['main'];
var climate = dartt['temp'];
var weather = climate - 32 * 5/9;
// print('Response status: ${response.statusCode}');
// print('Response body: ${json.decode(response.body)}');
// print(dart['main']);
// print(dartt['temp']);
var textHolder = '${weather.toString()}C';
setState(() {
c = textHolder;
});
}
#override
void initState() {
super.initState();
weath();
}
#override
Widget build(BuildContext context) {
var c = weath();
//print(textHolder);
//changeText();
return Scaffold(
body: Center(child: Column(
children: <Widget>[
Container(
padding: EdgeInsets.fromLTRB(20, 20, 20, 20),
child: Text(c),
),
]))
);
}
}
Just use setState((){}). Don't use return weath(), because async is a background thread and textView need UI.
var c = "";
#override
void initState() {
super.initState();
weath()
}
weath() async {
Position position = await Geolocator().getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
var url = 'https://api.openweathermap.org/data/2.5/weather?lat=${position.latitude}&lon=${position.longitude}&appid=myapiid';
print(url);
var response = await http.get(url);
var dart = json.decode(response.body);
var dartt = dart['main'];
var climate = dartt['temp'];
var weather = climate - 32 * 5/9;
setState(() {
c = '${weather}C'; } );
}
Add Future as return type, as you are returning the value inside async function
Future<String> weath() async {
Modify the Build method like
Widget build(BuildContext context) {
return FutureBuilder(
future: weath(),
builder: (ctx, snapshot) {
return Scaffold(
body: Center(
child: Column(children: <Widget>[
Container(
padding: EdgeInsets.fromLTRB(20, 20, 20, 20),
child: Text(snapshot.data.toString()),
),
])));
});
}
I'm experimenting with flutter, creating a small screen to fetch cryptocurrency data. I have three crypto name (BTC, ETH, LTC), each will be displayed on card, the rate on USD.
I can get the data for each currency, and display it. But in my code, if each data fetch took 1 second, the cards display will be updated after 3 seconds. All data will be fetched first, then screen updated using setState().
This is the initial working code
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'coin_data.dart' as coinData;
class PriceScreen extends StatefulWidget {
#override
_PriceScreenState createState() => _PriceScreenState();
}
class _PriceScreenState extends State<PriceScreen> {
String _selectedCurrency = "USD";
List<coinData.CoinData> _coinData = [];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Coin Ticker'),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
buildCoinCards(),
],
),
);
}
Card buildCoinCard(coinData.CoinData currentCoinData) {
return Card(
child: Padding(
padding: EdgeInsets.symmetric(vertical: 15.0, horizontal: 28.0),
child: Text(
'1 ${currentCoinData.coinName()} = ${currentCoinData.last} $_selectedCurrency',
),
),
);
}
buildCoinCards() {
List<Card> coinCards = [];
for (var currentCoinData in _coinData) {
coinCards.add(
buildCoinCard(currentCoinData),
);
}
return Column(
children: coinCards,
);
}
#override
void initState() {
super.initState();
for (String crypto in coinData.cryptoList) {
_coinData.add(
coinData.CoinData(
last: 0,
displaySymbol: "$crypto-$_selectedCurrency",
),
);
}
updateCoinData();
}
void updateCoinData() async {
var coinDataFetch =
await coinData.CoinData().getAllCoinData(_selectedCurrency);
setState(() {
_coinData = coinDataFetch;
});
}
}
I'd like to update each item everytime a HTTP call is success. So the card will be updated one by one (took 1 second each) instead of waiting for 3 seconds. So I change the updateCoinData() to this, but it's not working.
void updateCoinData() async {
for (coinData.CoinData currentCoinData in _coinData) {
var fetchCoinData = await currentCoinData.getCoinData(
currentCoinData.coinName(), _selectedCurrency);
setState(() {
currentCoinData = fetchCoinData;
print(
currentCoinData.coinName() + " " + currentCoinData.last.toString());
});
}
}
I suppose I cannot update the List item on setState()?
How do I achieve this update one-by-one?
Thanks