List<Event> events = [];
int currentPage = 1;
Dio dio = Dio();
void getEvents() async {
try {
var response =
await Dio().get('http://52.90.175.175/api/events/get?page=$currentPage');
var data = response.data["data"]["data"] as List;
setState(() {
events = data.map((i) => Event.fromJson(i)).toList();
});
print(events);
} catch (e) {
print(e);
}
}
This is how I fetch my events and 10 events per page is loading and here is my json response of API
my full json
Next page URL and next page decide by API and I want to know how to pagination with infinite_scroll_pagination for my widget
ListView.builder(
itemCount: events.length,
itemBuilder: (context, index) {
return ListTile(
contentPadding: const EdgeInsets.all(20),
title: Text(events[index].title),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(events[index].description),
Text("${events[index].start} - ${events[index].end}"),
],
),
);
},
),
no need to add any packages, add this code to initState
controller = new ScrollController()..addListener(_scrollListener);
and create this method.
_scrollListener() {
print(controller.position.extentAfter);
if (scrollController.position.maxScrollExtent == scrollController.offset) {
currentPage++;
getEvents();
}
}
Related
I have created an observable list and then storing data in the list from the api as below
class FeedsController extends GetxController {
final Rx<List<Stories>> _stories = Rx<List<Stories>>([]);
#override
void onInit() {
super.onInit();
getActiveStories();
}
List<Stories> get getStories {
return _stories.value;
}
Future<List<Stories>> getActiveStories() async {
var url = Uri.parse(storiesURL);
Map<String, Object> params = {'apikey': apiKey, 'userid': "8"};
await http.post(url, body: params).then((value) {
StoriesResponse storiesResponse = storiesResponseFromJson(value.body);
_stories.value = storiesResponse.stories;
}).onError((error, stackTrace) {
debugPrint('Error occurred while fetching stories response: ${error.toString()}');
});
return _stories.value;
}
}
Here is the code for displaying the Stories List
class _ActiveStoriesListState extends State<ActiveStoriesList> {
List<Story> _currentUserStories = [];
final FeedsController _feedsController = Get.find();
#override
void initState() {
Future.delayed(Duration.zero, fetchUserStories);
super.initState();
}
#override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Active Stories',
style: titleLargeTextStyle.copyWith(fontSize: 22, fontWeight: FontWeight.w600),),
const SizedBox(height: 10),
SizedBox(
height: 100,
child: Obx(
() => ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemBuilder: (ctx, index) =>
ActiveStoriesWidget(story: _currentUserStories[index]),
itemCount: _currentUserStories.length,
),
)),
],
);
}
void fetchUserStories() async {
List<Stories> stories = _feedsController.getStories;
stories = stories.where((story) => story.userId == '8').toList();
_currentUserStories = stories[0].story;
debugPrint('Active Stories Page: ${_currentUserStories.length}');
}
}
Solutions I have tried is that make only ListView observable (that didn't work), making ListView parent child Observable that also didn't work. I'm unable to understand where I'm missing. Below is the exception
Exception Screenshot
sample json data
{ "status": 200, "success": [ { "user_id": "4", "first_name": "Abu", "profileImage": "jayspur.com/RallyApp/public/uploads/userImages/…", "story": [ { "story": "jayspur.com/RallyApp/public/uploads/userStories/…", "addeddate": "2023-02-08 09:58:11" } ] } ] }
You are getting this error because you are not using any observable list inside your ListView.builder.
But before that you should convert your StatefullWidget to a StatelessWidget because in GetX, we don't need any StatefullWidget.
You can try the following code.
Controller
class FeedsController extends GetxController {
final Rx<List<Stories>> _stories = Rx<List<Stories>>([]);
List<Stories> currUserstories = [];
RxBool isLoading = false.obs;
#override
void onInit() {
super.onInit();
getActiveStories();
}
List<Stories> get getStories {
return _stories.value;
}
Future<List<Stories>> getActiveStories() async {
isLoading.value = true;
var url = Uri.parse("storiesURL");
Map<String, Object> params = {'apikey': apiKey, 'userid': "8"};
await http.post(url, body: params).then((value) {
StoriesResponse storiesResponse = storiesResponseFromJson(value.body);
_stories.value = storiesResponse.stories;
_stories.value =
_stories.value.where((story) => story.userId == '8').toList();
currUserstories = _stories.value[0];
}).onError((error, stackTrace) {
debugPrint(
'Error occurred while fetching stories response: ${error.toString()}');
});
isLoading.value = false;
return _stories.value;
}
}
View file:
class ActiveStoriesList extends StatelessWidget {
ActiveStoriesList({super.key});
final FeedsController _feedsController = Get.find();
#override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Active Stories',
style: titleLargeTextStyle.copyWith(
fontSize: 22, fontWeight: FontWeight.w600),
),
const SizedBox(height: 10),
SizedBox(
height: 100,
child: Obx(
() => _feedsController.isLoading.value
? const Center(
child: CircularProgressIndicator(),
)
: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemBuilder: (ctx, index) => ActiveStoriesWidget(
story: _feedsController.currUserstories[index]),
itemCount: _feedsController.currUserstories.length,
),
)),
],
);
}
}
You might have to tweak the code a bit but the core concept it you should do all your work inside the controller and only fetch the data in view file.
Also, you should only use the lifecycle which controller provides. Eg. onInit instead of initState.
If this dosen't work, try to modify your controller file such that you get the value in the list as you want in the controller file itself and you the list which was preseneted in controller in your view file.
Hope it helps.
This is my code-snippet
var _productes = [];
final FirebaseFirestore _firebaseFirestore =
FirebaseFirestore.instance;
getProducts() async {
Query query = _firebaseFirestore.collection("CartOrder");
var querySnapshot = await query.get();
_productes.addAll(querySnapshot.docs);
}
#override
void initState() {
getProducts();
super.initState();
}
for (var i = 0; i < _productes.length; i++) {
_myDocument = (_productes[i]["cart"] as List<dynamic>)
.map((m) => Map<String, dynamic>.from(m))
.toList();
}
return ListView.builder(
itemCount: _myDocument!.length,
itemBuilder: (itemBuilder, index) {
for (var element in usersModel!.modelUsersList) {
if (element.uid!.contains(_myDocument![index]["salleruid"])) {
element = element;
}
}
return usere(_myDocument![index], element);
// print(dty.contains(FirebaseAuth.instance.currentUser!.uid));
});
}
usere(product, element) {
return Row(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
// Text(modelUsersList.userName.toString()),
Text("${element.userName}"),
Text("${product["title"]}"),
],
),
),
],
);
}
I like to archive like the following image
I want to not repeat the name of the store and I want all the products that belong to it to appear together in the same box flutter
Thanks for the help
Thanks for the help
I've been looking for a solution to sort a list (ascending and descending) On Button Press inside of a FutureBuilder, that is a Future<List>, but can't seem to understand how to define it as a List and then sort it on a button press. So I call the API, the API returns some dummy value, it's gets built in the Future Builder and in a ListView.builder, now I want sort the list by id (or by any type for that matter) but the method is not working because the list is null. The code:
API Call for the dummy data:
Future<List<Post>> fetchPosts() async {
List<Post> posts = [];
final response = await http.get('https://jsonplaceholder.typicode.com/posts');
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
var postsJson = jsonDecode(response.body);
for (int i = 0; i < postsJson.length; i++) {
posts.add(Post.fromJson(jsonDecode(response.body)[i]));
}
return posts;
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load posts');
}
}
The Future Builder:
List<Post> posts = []; /// if a define it like this, the value is always null
Future<List<Post>> futurePosts;
#override
void initState() {
super.initState();
futurePosts = fetchPosts();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: SafeArea(
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
children: [
MaterialButton(color: Colors.grey, onPressed: (){
// here I am setting set to compare the values of all IDs so it can be sorted ascending and descending by number of ID every time I press the button
setState(() {
posts.sort((a, b) => a.id.compareTo(b.id));
});
},),
Container(
height: 1000,
child: FutureBuilder<List<Post>>(
future: futurePosts,
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
shrinkWrap: true,
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return Text('${snapshot.data[index].id}')
},
);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return Container();
},
),
But it seems my understanding and code is not working for me at this point. Any help is appreciated, thanks in advance!
You can move your posts.sort((a, b) => a.id.compareTo(b.id)); inside your Future function, before returning posts. And change the setState, to change the state of a boolean, which sorts or not.
You can change like this:
//define a boolen
bool _isSorted =false;
Future<List<Post>> fetchPosts(bool sortORnot) async {
List<Post> posts = [];
final response = await http.get('https://jsonplaceholder.typicode.com/posts');
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
var postsJson = jsonDecode(response.body);
for (int i = 0; i < postsJson.length; i++) {
posts.add(Post.fromJson(jsonDecode(response.body)[i]));
}
if (sortORnot) {posts.sort((a, b) => a.id.compareTo(b.id));}// this will sort only if you wanted your list sorted.
return posts;
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load posts');
}
}
Change your FutureBuilder to this:
FutureBuilder<List<Post>>(
future:_isSorted? fetchPosts(true):fetchPosts(false),
builder: (context, snapshot) {
and setState to this:
setState(() {
_isSorted = !_isSorted; //this flips the value whenever you press it.
});
Now, in your future builder, you should get the posts sorted, can you try this?
Something like this, I think, should work:
List<Post> posts;
#override
void initState() {
super.initState();
fetchPosts().then((items) {
setState(() {
posts = items;
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: SafeArea(
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(children: [
MaterialButton(
color: Colors.grey,
onPressed: () {
setState(() {
if (posts != null) {
posts = posts.toList();
posts.sort((a, b) => a.id.compareTo(b.id));
}
});
},
),
Container(
height: 1000,
child: (posts != null)
? ListView.builder(
shrinkWrap: true,
itemCount: posts.length,
itemBuilder: (context, index) {
return Text('${posts[index].id}');
},
)
: Container(),
)
]),
),
),
);
}
Your posts field is always empty because you never assign data to that field. And this is the main problem. Try it out.
Pretty new to flutter. Trying to fit pagination loading from API into existing code but all the resources seem to point towards loading more from a static list.
Widget build(BuildContext context) {
return widget.placesList.isEmpty
? CircularLoadingWidget(height: 200)
: Container(
height: 200,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: widget.placesList.length,
itemBuilder: (context, index) {
return GestureDetector(
onTap: () {
},
child: PlaceCardWidget(place: widget.placesList.elementAt(index)),
);
},
),
);
}
I'm a little confused about streams and how to make an endless stream from a paginated API.
getCurrentLocation().then((LocationData _locationData) async {
final Stream<Place> stream = await getNearPlaces(_locationData, _locationData);
stream.listen((Place _place) {
setState(() => placesList.add(_place));
}, onError: (a) {
print(a);
}, onDone: () { print('Places: ' + placesList.length.toString()); });
});
Future<Stream<Place>> getNearPlaces(LocationData myLocation) async {
String _nearParams = '';
String _orderLimitParam = '';
if (myLocation != null) {
_orderLimitParam = 'orderBy=distance&perPage=10';
_nearParams =
'&myLon=${myLocation.longitude}&myLat=${myLocation.latitude}';
}
final String url = '${GlobalConfiguration().getString('api_base_url')}places/?$_nearParams&$_orderLimitParam';
final client = new http.Client();
final streamedRest = await client.send(http.Request('get', Uri.parse(url)));
return streamedRest.stream
.transform(utf8.decoder)
.transform(json.decoder)
.map((data) => data['results'])
.expand((data) => (data as List))
.map((data) {
return Place.fromJSON(data);
});
}
API format
{
"count": 119,
"next": "../places/?page=4",
"previous": "../places/?page=2",
"results": [],
}
Any guidance greatly appreciated.
Thanks!
I have a futureBuilder widget displaying records from a database, and I'm getting those records from an async future network request. There are a few choiceChip widgets that onSelected assign a new future to the FutureBuilders future.
The first time a choiceChip is clicked the new future is called and created but the displayed records don't update. If you click the same choiceChip a second time, the records update and are displayed correctly.
Why doesn't the futureBuilder update on the first click of the choiceChip even though the new future is being called and assigned correctly?
UPDATE: I switched from a future to a stream and added a check to see if the ConnectionState was done. That seems to have done the trick.
class _HousingFeedState extends State<HousingFeed> with AutomaticKeepAliveClientMixin<HousingFeed> {
Future<List<Housing>> _future;
#override
void initState() {
super.initState();
_future = housingFeed(0, "");
}
Widget _chipRow = new Container(
child: SingleChildScrollView(
child: Row(
children: List<Widget>.generate(
5,
(int index) {
return Padding(
padding: EdgeInsets.only(left: 5.0),
child: ChoiceChip(
selected: _housingType == index,
onSelected: (bool selected) {
setState(() {
_housingType = index;
_future = housingFeed(subcategoryMap[index], '');
});
},
),
);
},
).toList(),
),
),
);
Widget housingBuilder = FutureBuilder<List<Housing>>(
future: _future,
builder: (context, snapshot) {
...
}
);
}
Future<List<Housing>> housingFeed(int subcategoryId, String search) async {
String url = "https://...";
final response = await http.post(url,
headers: {HttpHeaders.contentTypeHeader: 'application/json'},
body: jsonEncode({
"id": userId,
"filter": {"id": subcategoryId},
"search": search
}));
if (response.statusCode == 200) {
var housingListings = List<Housing>();
var jsonData = json.decode(response.body);
jsonData['response'].forEach((listing) {
housingListings.add(Housing.fromJson(listing));
});
return housingListings;
} else {
throw Exception('Failed to load');
}
}