I have a problem while doing API integration in Flutter - flutter

While trying to fetch data using API I didn't get the details . Instead of details I only get null.
How should I solve this?
Hera is my Code .
my screen page code
class ModuleListScreen extends StatefulWidget {
const ModuleListScreen({Key? key}) : super(key: key);
#override
_ModuleListScreenState createState() => _ModuleListScreenState();
}
class _ModuleListScreenState extends State<ModuleListScreen> with HttpMixin {
DatabaseHelper _dbHelper = DatabaseHelper();
List<Item> modules = [];
List<UserTable> userdetails = [];
String userId = '';
String accountId = '';
#override
void initState() {
super.initState();
_dbHelper.getAllUserData().then((value)async{
userdetails = value;
var response = await getmoduleList(value[0].userId.toString(),value[0].accountId.toString());
response.forEach((element) {
setState(() {
modules.add(element);
});
print('Test Printing ${element.pkgSequence}');
print('Test Printing ${modules[0].id}');
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.blue.shade300,
appBar: AppBar(
backgroundColor: Colors.pink,
actions: [
Padding(
padding: const EdgeInsets.all(5.0),
child: Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.white, width: 3),
color: Colors.blue,
borderRadius: BorderRadius.circular(50)),
child: Padding(
padding: const EdgeInsets.all(5.0),
child: Image.asset('assets/images/icons/Back.png'),
)),
)
],
title: Center(child: Text('Subject Name')),
leading: Padding(
padding: const EdgeInsets.all(5.0),
child: Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.white, width: 3),
color: Colors.blue,
borderRadius: BorderRadius.circular(50)),
child: Padding(
padding: const EdgeInsets.all(5.0),
child: Image.asset('assets/images/icons/ride.png'),
)),
),
),
body: Container(
child:
ListView.builder(
itemCount: modules.length,
itemBuilder: (context, index) {
return Container(
height: MediaQuery.of(context).size.height / 3,
margin: EdgeInsets.all(3),
child: Column(
children: [
Container(
padding: EdgeInsets.fromLTRB(
MediaQuery.of(context).size.height * .15,
5,
MediaQuery.of(context).size.height * .15,
5),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50),
color: Colors.grey),
child: Text(modules[index].title.toString()),
),
Expanded(
child: Padding(
padding: const EdgeInsets.fromLTRB(10, 0, 10, 0),
child: Container(
height: MediaQuery.of(context).size.height / 3,
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(10),
color: Colors.white,
),
child: ListView.builder(
itemCount: 2,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
'{article.chapter}',
style: TextStyle(
color: Colors.grey,
fontSize: 18,
fontWeight: FontWeight.w700),
),
Image(
height: 15,
image: AssetImage(
'assets/images/icons/Download.png'),
)
],
),
);
}),
),
),
)
],
));
})
),
);
}
}
My model page
class ModuleList {
ModuleList({
this.items,
this.subject,
this.grade,
});
List<Item>? items;
String? subject;
String? grade;
factory ModuleList.fromMap(Map<String, dynamic> map) => ModuleList(
items: map["items"] != null ? List<Item>.from(map["items"].map((x) => Item.fromMap(x))):[],
// items: List<Item>.from(json["items"].map((x) => Item.fromJson(x))),
subject: map["subject"],
grade: map["grade"],
);
Map<String, dynamic> toMap() => {
"items": items,
"subject": subject,
"grade": grade,
};
}
class Item {
Item({
this.sequenceno,
this.id,
this.chapter,
this.title,
this.packageDescription,
this.ageLevel,
this.pkgSequence,
this.packagescors,
});
int? sequenceno;
String? id;
String? chapter;
String? title;
String? packageDescription;
List<int>? ageLevel;
String? pkgSequence;
List<Packagescors>? packagescors;
Item.fromMap(Map<String, dynamic> map) {
Item(
sequenceno: map["sequenceno"],
id: map["_id"],
chapter: map["chapter"],
title: map["title"],
packageDescription: map["package_description"],
ageLevel: List<int>.from(map["age_level"].map((x) => x)),
pkgSequence: map["pkg_sequence"],
// packagescors: json["packagescors"] != null ? null : Packagescors.fromJson(json["packagescors"]),
packagescors: map["packagescors"] != null
? List<Packagescors>.from(
map["device_details"].map((x) => Packagescors.fromMap(x)))
: [],
);
}
Map<String, dynamic> toMap() => {
"sequenceno": sequenceno,
"_id": id,
"chapter": chapter,
"title": title,
"package_description": packageDescription,
"age_level": List<dynamic>.from(ageLevel!.map((x) => x)),
"pkg_sequence": pkgSequence,
"packagescors": packagescors,
};
}
class Packagescors {
Packagescors({
this.score,
this.date,
});
List<int>? score;
List<String>? date;
factory Packagescors.fromMap(Map<String, dynamic> map) => Packagescors(
score: List<int>.from(map["score"].map((x) => x)),
date: List<String>.from(map["date"].map((x) => x)),
);
Map<String, dynamic> toMap() => {
"score": List<dynamic>.from(score!.map((x) => x)),
"date": List<dynamic>.from(date!.map((x) => x)),
};
}
My http_mixin code for the above model
Future<List<Item>> getmoduleList(
String userId, String accountId) async {
final queryParameters ={
'subject':'Maths',
'grade':'6'
};
final response = await http
.get(Uri.https(_baseUrl, "MY URI",queryParameters), headers: {
'Content-Type': 'application/json',
'user-id': userId,
'account-id': accountId,
});
List <Item> jsonresponse = json.decode(response.body)['data']['items'].map<Item>((e)=>Item.fromMap(e)).toList();
print((response.body));
return jsonresponse;
}
1.This is My code. Here I want to fetch data from API. Now the result I got when I fetch is null.
I created the model using quick type also done some changes in the model.

Related

Filter search filter data showing from Api using provider

how to implement search filter with API using provider? i have post Api when user hit Api it send back data to the user
My api
Future<List<Searchmodel>>Search(String keyword) async {
final response=await http.post(Uri.parse('https://example.com/api/library/search'),body: {
'Keyword': keyword,
});
if(response.statusCode==200){
final json=response.body..toString().replaceAll("\n","");
var data=jsonDecode(json);
final Iterable fetch = data["success"];
return fetch.map((category) => Searchmodel.fromJson(category)).toList();
}else{
throw Exception("Unable to perform request!");
}
}
//model class
class Searchmodel {
Searchmodel({
required this.id,
required this.name,
required this.file,
required this.categoryId,
required this.subcategoryId,
required this.userId,
required this.status,
required this.createdAt,
required this.updatedAt,});
Searchmodel.fromJson(dynamic json) {
id = json['id'];
name = json['name'];
file = json['file'];
categoryId = json['category_id'];
subcategoryId = json['subcategory_id'];
userId = json['user_id'];
status = json['status'];
createdAt = json['created_at'];
updatedAt = json['updated_at'];
}
int? id;
String? name;
String? file;
int? categoryId;
int? subcategoryId;
String? userId;
String? status;
String? createdAt;
String? updatedAt;
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['id'] = id;
map['name'] = name;
map['file'] = file;
map['category_id'] = categoryId;
map['subcategory_id'] = subcategoryId;
map['user_id'] = userId;
map['status'] = status;
map['created_at'] = createdAt;
map['updated_at'] = updatedAt;
return map;
}
}
//UI
import 'package:flutter/material.dart';
import 'package:livinghopegeetzaboor/Statemanagment/Library/LibraryProvider.dart';
import 'package:livinghopegeetzaboor/constant/AppColor.dart';
import 'package:livinghopegeetzaboor/sacreen/Geet/Geetsubcategory.dart';
import 'package:livinghopegeetzaboor/services/Services.dart';
import 'package:provider/provider.dart';
class Homepage extends StatefulWidget {
#override
State<Homepage> createState() => _HomepageState();
}
class _HomepageState extends State<Homepage> {
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Center(
child: Padding(
padding: EdgeInsets.fromLTRB(0, 0, 0, 0),
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
height: 100,
width: 100,
child: Image.asset('images/logo.png')
),
// Note: Same code is applied for the TextFormField as well
// Note: Same code is applied for the TextFormField as well
// Note: Same code is applied for the TextFormField as well
Padding(
padding: EdgeInsets.all(40),
child:Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20.0),
color: AppColor.color,
),
height: 80,
child: Padding(
padding: EdgeInsets.all(8.0),
child: Row(
children: [
Expanded(
child: TextField(
decoration: InputDecoration(
suffixIcon: Icon(Icons.search,
size: 40,
),
enabledBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.white, width:2),
),
filled: true, //<-- SEE HERE
fillColor: Colors.white,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20),
),
hintText: 'Search for any songs',
),
),
),
SizedBox(width: 3,),
// Container(
// height: 59,
// width: 59,
// color:Colors.white,
// constraints: const BoxConstraints(
//
// ),
// // child: Icon(
// // Icons.search_sharp,
// // size: 40,
// // color: AppColor.color,
// // ),
// )
],
),
),
),
),
Consumer<LibraryProvider>(
builder:(BuildContext context, value, Widget? child) {
if(value.isloading){
return CircularProgressIndicator(
color: AppColor.color,
);
}else{
return GridView.builder(
itemCount:value.library.length,
scrollDirection: Axis.vertical,
shrinkWrap: true,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 4.0,
mainAxisSpacing: 4.0
),
itemBuilder: (BuildContext context, int index){
var subtitle=value.library[index].name2;
return Padding(
padding: EdgeInsets.all(10),
child: Material(
color: Colors.white.withOpacity(0.0),
child: InkWell(
splashColor: Colors.orange,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
color: Colors.black,
),
//color: Colors.black,
height:200,
width: 200,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: EdgeInsets.all(5),
child: Center(
child: Text(value.library[index]!.name.toString(),style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 18
),),
),
),
SizedBox(height: 4,),
Padding(
padding: EdgeInsets.fromLTRB(10, 0, 0, 0),
child: Center(
child: subtitle!=null ? Text(value.library[index].name2.toString(),style: TextStyle(
color: Colors.white,
fontSize: 12
),):Text('',style: TextStyle(
color: Colors.white,
fontSize: 12
),)
),
),
],
),
),
onTap: (){
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Geetsubcategory(id: value.library[index].id,)),
);
},
),
),
);
},
);
}
},
)
],
),
// your main content
),
),
)
);
}
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_){
Provider.of<LibraryProvider>(context,listen: false).fetchlibary();
// Add Your Code here.
});
}
}
You need to add the api call from inside your provider function.
Like this
class SearchProvider with ChangeNotifier, DiagnosticableTreeMixin {
List<dynamic>? _items;
List<dynamic>? get items => _items;
void searchItems(String val) async {
_items = await ApiCall.search(val);
notifyListeners();
}
}
You can create a common object of provider on the page to use throughout your page like this.
SearchProvider _provider = SearchProvider();
and use it like this in your provider and consumer on the same page
ChangeNotifierProvider<SearchProvider>(
create: (_) => _provider,
child: Column(
children: [
... // other code
Consumer<SearchProvider>(
builder: (context, provider, w) {
if (provider.items != null && provider.items!.isNotEmpty) {
return SearchList(list: provider.items);
}
return const Center(child: Text("Nothing found"));
},
),
]),
),
Then setup one TextField to type & fire search query. You can setup onSubmitted callback of the Textfield to call your provider method.
TextField(
onSubmitted: (val) {
if(val.length > 0){
_provider.searchItems(val);
}
else {
_provider.getAll();
}
},
decoration: const InputDecoration(
labelText: 'Search',
suffixIcon: Icon(Icons.search),
),
Using this code will call the provider method when you press enter after typing some query in TextField. That provider method will then call the api & store the response in a List then call notifyListeners() from that method to notify all the consumers. Those consumer then try to read the list & create a listview if they find data in the list.
Here is an example of full working code:
https://dartpad.dev/?id=a5950f2da95d58e32dc9176433d9bcb3
I have also added the onload list which can be filtered from api itself & it user delete search query it will again call the full list api for data.
Hope this will help you understand things better using provider.

Search from a list of Firebase Users with TextField and StreamProvider in Flutter

I'm building a chat app with Firebase in flutter and I want to be able to search from a list of users,. I also want that when no text is typed, no user should be shown
I tried a lot of things but I never got it right. This is what I did :
search_page.dart:
class SearchPage extends StatefulWidget {
const SearchPage({Key? key}) : super(key: key);
#override
State<SearchPage> createState() => _SearchPageState();
}
class _SearchPageState extends State<SearchPage> {
TextEditingController searchController = TextEditingController();
#override
void initState() {
super.initState();
searchController.addListener(_onSearchChanged);
}
_onSearchChanged() {
print(searchController.text);
}
#override
void dispose() {
searchController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return StreamProvider<List<AppUserData>>.value(
initialData: [],
value: DatabaseService().users,
child: Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: dDarkGrey,
body:
Column(crossAxisAlignment: CrossAxisAlignment.center, children: [
const SizedBox(
height: 3,
),
Stack(
alignment: Alignment.center,
children: [
Container(
height: 90,
decoration: BoxDecoration(color: dDarkGrey, boxShadow: [
BoxShadow(
color: dBlack.withOpacity(0.16),
spreadRadius: 3,
blurRadius: 3,
offset: const Offset(0, 4))
]),
),
Column(
children: [
const SizedBox(
height: 20,
),
Row(
children: [
IconButton(
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => const HomePage()));
},
icon: const Icon(SocketIconv2.ic_back),
color: dLightGrey,
),
SizedBox(
width: MediaQuery.of(context).size.width - 60,
child: TextField(
enabled: true,
controller: searchController,
style: const TextStyle(color: dLightGrey),
decoration: const InputDecoration(
contentPadding:
EdgeInsets.fromLTRB(0, 0, 0, 0),
filled: true,
fillColor: dDarkGrey,
prefixIcon: Icon(
SocketIconv2.ic_search,
color: dLightGrey,
),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(15))),
hintStyle: TextStyle(
color: dLightGrey,
fontFamily: 'SegoeUI',
fontSize: 18,
fontWeight: FontWeight.w300),
hintText: 'Search',
))),
],
),
],
),
],
),
// search bar
SizedBox(
height: MediaQuery.of(context).size.height - 95,
width: MediaQuery.of(context).size.width,
child: SearchList(
controller: searchController,
),
)
])),
);
}
}
search_list.dart:
class SearchList extends StatelessWidget {
SearchList({Key? key, required this.controller}) : super(key: key);
final TextEditingController controller;
#override
Widget build(BuildContext context) {
final users = Provider.of<List<AppUserData>>(context);
return Scaffold(
backgroundColor: Colors.transparent,
body: ListView.separated(
itemBuilder: (context, index) {
if (controller.text.isEmpty) {
return Container();
}
if (controller.text.isNotEmpty) {
return searchAccount(context, name, username, users[index]);
}
if (users[index].name.startsWith(controller.text.toLowerCase())) {
return searchAccount(context, name, username, users[index]);
} else {
return Container();
}
},
itemCount: users.length,
separatorBuilder: (context, index) => const SizedBox(height: 20),
));
}
}
search_account.dart:
Widget searchAccount(
BuildContext context, String name, String username, AppUserData users) {
return Row(
children: [
const SizedBox(
width: 20,
),
Row(
children: [
ClipOval(
child: Image.asset(
imagePp,
scale: 9,
),
),
const SizedBox(
width: 30,
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(users.name,
style: SegoeUiPreset(dLightGrey).customTileName()),
Text(users.username,
style: SegoeUiPreset(dLightGrey).customTileSubtitle())
],
)
],
),
],
);
}
user.dart:
class AppUser {
final String? uid;
AppUser({this.uid});
}
class AppUserData {
final String? uid;
final String name;
final String username;
AppUserData({this.uid, required this.name, required this.username});
}
database.dart:
class DatabaseService {
final String? uid;
DatabaseService({this.uid});
final CollectionReference chatRoomCollection =
FirebaseFirestore.instance.collection("chatrooms");
final CollectionReference userCollection =
FirebaseFirestore.instance.collection("users");
Future<void> saveUser(String name, String username) async {
return await userCollection
.doc(uid)
.set({'name': name, 'username': username});
}
AppUserData _userFromSnapshot(DocumentSnapshot snapshot) {
return AppUserData(
name: snapshot['name'],
uid: snapshot.id,
username: snapshot['username']);
}
Stream<AppUserData> get user {
return userCollection.doc(uid).snapshots().map(_userFromSnapshot);
}
List<AppUserData> _userListFromSnapshot(QuerySnapshot snapshot) {
return snapshot.docs.map((doc) {
return _userFromSnapshot(doc);
}).toList();
}
Stream<List<AppUserData>> get users {
return userCollection.snapshots().map(_userListFromSnapshot);
}
}
Got any hints ? I'm a begginner :/
Thank you in advance :)

I tried to get data from firestore but display this error "The instance member 'mapRecords' can't be accessed in an initializer. " on Flutter

I tried to get data from firestore but display this error "The instance member 'mapRecords' can't be accessed in an initializer. " on Flutter.
Screenshots of errors
https://drive.google.com/drive/folders/1toBdn9h4-LgBLl5ybG63brgXmk5G0h3F?usp=sharing
my code
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:hexcolor/hexcolor.dart';
import 'package:kathana/utils/config.dart';
import '../screens/wordsBefore18/database/words12model.dart';
class uitry5 extends StatefulWidget {
const uitry5({Key? key}) : super(key: key);
#override
State<uitry5> createState() => _uitry5State();
}
class _uitry5State extends State<uitry5> {
List<String> wordList = [];
Future _fetch = Future(() async {
var records = await FirebaseFirestore.instance.collection('12words').get();
return mapRecords(records);
});
List<Words12> mapRecords(QuerySnapshot<Map<String, dynamic>> records) {
var wordList = records.docs
.map(
(words12) {
print(words12);
return
Words12(
id: words12.id,
wordName: words12['wordName'],
categoryName: words12['categoryName']
);}
.toList();
return wordList;
}
#override
void initState() {
super.initState();
print(wordList);
}
List<String> selectedWord = [];
List<String>? deSelectedWord = [];
#override
Widget build(BuildContext context) {
double height = MediaQuery.of(context).size.height;
double width = MediaQuery.of(context).size.width;
return Scaffold(
body: Container(
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage(Config.app_background4), fit: BoxFit.fill),
),
child: SafeArea(
child: Center(
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 14, right: 0),
child: Column(
children: [
SizedBox(
width: width * 0.94,
height: height * 0.30,
child: Column(
children: <Widget>[
const SizedBox(height: 16),
Wrap(
children: wordList.map(
(word) {
bool isSelected = false;
if (selectedWord!.contains(word)) {
isSelected = true;
}
return GestureDetector(
onTap: () {
if (!selectedWord!.contains(word)) {
if (selectedWord!.length < 50) {
selectedWord!.add(word);
deSelectedWord!.removeWhere(
(element) => element == word);
setState(() {});
print(selectedWord);
}
} else {
selectedWord!.removeWhere(
(element) => element == word);
deSelectedWord!.add(word);
setState(() {
// selectedHobby.remove(hobby);
});
print(selectedWord);
print(deSelectedWord);
}
},
child: Container(
margin: const EdgeInsets.symmetric(
horizontal: 5, vertical: 4),
child: Container(
padding: const EdgeInsets.symmetric(
vertical: 5, horizontal: 12),
decoration: BoxDecoration(
color: isSelected
? HexColor('#0000FF')
: HexColor('#D9D9D9'),
borderRadius:
BorderRadius.circular(18),
border: Border.all(
color: isSelected
? HexColor('#0000FF')
: HexColor('#D9D9D9'),
width: 2)),
child: Text(
word,
style: TextStyle(
color: isSelected
? Colors.black
: Colors.black,
fontSize: 14,
fontWeight: FontWeight.w600),
),
),
),
);
},
).toList(),
),
],
),
),
],
),
),
],
))),
),
);
}
}
model
import 'dart:convert';
Words12 words12FromJson(String str) => Words12.fromJson(json.decode(str));
String words12ToJson(Words12 data) => json.encode(data.toJson());
class Words12 {
Words12({
required this.id,
required this.wordName,
required this.categoryName,
});
String id;
String wordName;
String categoryName;
factory Words12.fromJson(Map<String, dynamic> json) => Words12(
id: json["id"],
wordName: json["wordName"],
categoryName: json["categoryName"],
);
Map<String, dynamic> toJson() => {
"id": id,
"wordName": wordName,
"categoryName": categoryName,
};
}
How do I resolve this and get data from the database
You can use late before future.
late Future _fetch = ...
Also I will prefer shifting mapRecords before _fetch and FutureBuilder for future.

How to filter list item in getx

I have a to-do app, where I have a list of items with scheduled date and time, title, details, and task done or not. I want to filter the list of todos depending on if its done or not done, How do I implement this in the getx Controller.
Model:
class Todo {
String title;
String details;
String? date;
String? time;
bool done;
bool dateAndTimeEnabled;
int id;
Todo(
{required this.title,
required this.details,
required this.date,
required this.time,
this.dateAndTimeEnabled = true,
required this.id,
this.done = false});
factory Todo.fromJson(Map<String, dynamic> json) => Todo(
id: json['id'],
title: json['title'],
details: json['details'],
done: json['done'],
date: json['date'],
time: json['time'],
dateAndTimeEnabled: json['dateAndTimeEnabled']);
Map<String, dynamic> toJson() => {
'id': id,
'title': title,
'details': details,
'done': done,
'date': date,
'time': time,
'dateAndTimeEnabled': dateAndTimeEnabled
};
}
Getx controller:
class TodoController extends GetxController {
var todos = <Todo>[].obs;
#override
void onInit() {
List? storedTodos = GetStorage().read<List>('todos');
if (storedTodos != null) {
todos.assignAll(storedTodos.map((e) => Todo.fromJson(e)).toList());
}
ever(todos, (_) {
GetStorage().write('todos', todos.toList());
});
super.onInit();
}
}
Update
#override
void initState() {
todoController.getDoneTodos();
super.initState();
}
GestureDetector(
onTap: () {
Get.to(() => const doneTodos());
},
child: Padding(
padding: const EdgeInsets.only(top: 20.0, left: 14.0, right: 12.0),
child: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('${todoController.doneTodos.length}', style: Theme.of(context).textTheme.headline1,),
Text("Done", style: Theme.of(context).textTheme.headline1)
],),
padding: const EdgeInsets.symmetric(horizontal: 15.0, vertical: 20.0),
height: 138.0,
width: double.infinity,
decoration: BoxDecoration(
color: Theme.of(context).canvasColor,
boxShadow: [
BoxShadow(
color: Theme.of(context).shadowColor,
offset: const Offset(2.5, 2.5),
blurRadius: 5.0,
spreadRadius: 1.0,
),
],
borderRadius:
BorderRadius.circular(14.0))
),
),
),
I tried to wrap the Text widget with Obx but it throws this error: FlutterError (setState() or markNeedsBuild() called during build.
In your controller:
var doneTodos = <Todo>[].obs;
getDoneTodos(){
doneTodo.assignAll(todos.where(element)=>element.done == true).toList());
}

only single row comes from the json api

I am beginner in flutter ,I used an API of soccer to get some information of player transferts ,so I have created a model class that contains only the information that I need to ,but when I executed, I had this error:
E/flutter ( 5073): [ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: type 'String' is not a subtype of type 'int' of 'index'
E/flutter ( 5073): #0 new Transferts.fromJson (package:tl_fantasy/models/transfert_json.dart:12:26)
E/flutter ( 5073): #1 _PlayerDetailsState.getTeams.<anonymous closure>.<anonymous closure> (package:tl_fantasy/players/player_details.dart:45:45)
So I changed my model class
if i put this in the model class it works when i put it for example json['transfers'][0]['date'], but the problem is it gives me only the first result , what i need is all results, how to replace[0] by a kind of index or something? how to take all elements?
Here the json that i am trying to access:
{
"response": [
{
"player": {
"id": 35845,
"name": "Hernán Darío Burbano"
},
"update": "2020-02-06T00:08:15+00:00",
"transfers": [
{
"date": "2019-07-15",
"type": "Free",
"teams": {
"in": {
"id": 2283,
"name": "Atlas",
"logo": "https://media.api-sports.io/football/teams/2283.png"
}
}
},
{
"date": "2019-01-01",
"type": "N/A",
"teams": {
"in": {
"id": 1937,
"name": "Atletico Atlas",
"logo": "https://media.api-sports.io/football/teams/1937.png"
}
}
}
]
}
]
}
Here my model class tranfert_json:
class Response {
Player player;
String update;
List<Transfers> transfers;
Response({this.player, this.update, this.transfers});
Response.fromJson(Map<String, dynamic> json) {
player = json['player'] != null ? new Player.fromJson(json['player']) : null;
update = json['update'];
if (json['transfers'] != null) {
transfers = new List<Transfers>();
json['transfers'].forEach((v) { transfers.add(new Transfers.fromJson(v)); });
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.player != null) {
data['player'] = this.player.toJson();
}
data['update'] = this.update;
if (this.transfers != null) {
data['transfers'] = this.transfers.map((v) => v.toJson()).toList();
}
return data;
}
}
class Player {
int id;
String name;
Player({this.id, this.name});
Player.fromJson(Map<String, dynamic> json) {
id = json['id'];
name = json['name'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['name'] = this.name;
return data;
}
}
class Transfers {
String date;
String type;
Teams teams;
Transfers({this.date, this.type, this.teams});
Transfers.fromJson(Map<String, dynamic> json) {
date = json['date'];
type = json['type'];
teams = json['teams'] != null ? new Teams.fromJson(json['teams']) : null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['date'] = this.date;
data['type'] = this.type;
if (this.teams != null) {
data['teams'] = this.teams.toJson();
}
return data;
}
}
class Teams {
In teamIn;
Teams({this.teamIn});
Teams.fromJson(Map<String, dynamic> json) {
teamIn = json['in'] != null ? new In.fromJson(json['in']) : null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.teamIn != null) {
data['in'] = this.teamIn.toJson();
}
return data;
}
}
class In {
int id;
String name;
String logo;
In({this.id, this.name, this.logo});
In.fromJson(Map<String, dynamic> json) {
id = json['id'];
name = json['name'];
logo = json['logo'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['name'] = this.name;
data['logo'] = this.logo;
return data;
}
}
Here my player_details class:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:tl_fantasy/models/transfert_json.dart';
class PlayerDetails extends StatefulWidget {
int id;
String name;
String lastname;
String image;
String club;
String position;
String nationality;
String age;
int matches;
String goals;
String assists;
String saves;
PlayerDetails({this.id,this.name, this.lastname,this.image, this.club, this.position,
this.nationality, this.age, this.matches, this.goals, this.assists, this.saves});
#override
_PlayerDetailsState createState() => _PlayerDetailsState();
}
class _PlayerDetailsState extends State<PlayerDetails> {
List<Response> teams = [];
Future<void> getTeams(int id) async {
http.Response response = await http.get(
'https://v3.football.api-sports.io/transfers?player=$id',
headers: {'x-rapidapi-key': 'c52370f8295e1525b7f7ba38655e243f',
'x-rapidapi-host':'v3.football.api-sports.io'});
String body = response.body;
var data = jsonDecode(body);
List<dynamic> clubList = data['response'];
setState(() {
teams = clubList
.map((dynamic item) => Response.fromJson(item))
.toList();
});
}
#override
void initState() {
super.initState();
getTeams(widget.id);
}
#override
Widget build(BuildContext context) {
if(widget.matches == null ){
widget.matches == 0;
}
if(widget.goals == null ){
widget.goals == "0";
}
if(widget.assists == null ){
widget.assists == "0";
}
if(widget.saves == null ){
widget.saves == "0";
}
List<Stats> stats = [
Stats("Matches", widget.matches.toString() ),
Stats("Goals", widget.goals ),
Stats("Assists", widget.assists ),
Stats("Saves", widget.saves ),
];
return Scaffold(
appBar: AppBar(
title: Text("Player Details"),
backgroundColor: Colors.blue[300],
elevation: 0.0,
),
body: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
colors: [Colors.purple, Colors.blue])
),
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [Colors.purple, Colors.black38])),
child: ListView(
children: [
SizedBox(
height: 20,
),
Container(
margin: EdgeInsets.fromLTRB(8.0,0,8.0,0),
width: double.infinity,
child: Card(
elevation: 4.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
child: Padding(
padding: const EdgeInsets.all(16.0),
child:
Row(
children: <Widget>[
Container(
height: 60,
width: 60,
child:
Image.network(this.widget.image,
),
),
const SizedBox(width:10.0),
Spacer(),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget> [
Text(widget.name, style: TextStyle( fontWeight:FontWeight.bold,
fontSize: 18.0,
)),
Text(widget.lastname, style: TextStyle( fontWeight:FontWeight.bold,
fontSize: 18.0,
)),
const SizedBox(height: 5.0, ),
Text(widget.club, style: TextStyle( fontWeight:FontWeight.bold,
fontSize: 18.0,
)),
const SizedBox(height: 5.0, ),
Text("Role : "+widget.position, style: TextStyle( fontWeight:FontWeight.bold,
fontSize: 18.0, color: Colors.grey[600],
)),
const SizedBox(height: 5.0, ),
Text("Age : "+widget.age, style: TextStyle( fontWeight:FontWeight.bold,
fontSize: 18.0, color: Colors.grey[600],
)),
const SizedBox(height: 5.0, ),
Text("Nationality : "+widget.nationality, style: TextStyle( fontWeight:FontWeight.bold,
fontSize: 18.0, color: Colors.grey[600],
)),
],
),
],
),
),
),
),
Container(
margin: EdgeInsets.fromLTRB(10, 15, 0, 0),
child: Text(
"Season Stats",
style: TextStyle(fontSize: 17, fontWeight: FontWeight.w900, color: Colors.white),
),
),
SizedBox(
height: 10,
),
Container(
padding: EdgeInsets.all(12.0),
child: GridView.builder(
shrinkWrap: true,
itemCount: stats.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 4.0,
mainAxisSpacing: 4.0
),
itemBuilder: (BuildContext context, int index){
return Card(
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
alignment: Alignment.topCenter,
padding: EdgeInsets.fromLTRB(0, 5, 0, 0),
child: Text(stats[index].result,style: TextStyle(fontSize: 20.0)),
),
Container(
alignment: Alignment.bottomCenter,
child: Text(stats[index].title,style: TextStyle(fontSize: 25.0)),),
]
),
),
);
},
)
),
SizedBox(
height: 10,
),
Container(
margin: EdgeInsets.fromLTRB(10, 0, 0, 10),
child: Text(
"Teams",
style: TextStyle(fontSize: 17, fontWeight: FontWeight.w900, color: Colors.white),
),
),
SizedBox(
height: 10,
),
Container(
margin: EdgeInsets.fromLTRB(5, 0, 5, 0),
child: ListView.builder(
shrinkWrap: true,
physics : NeverScrollableScrollPhysics(),
itemBuilder: (context, index){
return Card(
elevation: 4.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
child: Padding(
padding: const EdgeInsets.all(16.0),
child:
Row(
children: <Widget>[
CircleAvatar(
backgroundImage: NetworkImage(teams[index].transfers[index].teams.teamIn.logo),
),
const SizedBox(width:10.0),
Spacer(),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget> [
Text(teams[index].transfers[index].teams.teamIn.name, style: TextStyle( fontWeight:FontWeight.bold,
fontSize: 18.0,
)),
const SizedBox(height: 5.0, ),
Text("joined : "+teams[index].transfers[index].date, style: TextStyle( fontWeight:FontWeight.bold,
fontSize: 18.0, color: Colors.grey[600],
)),
],
),
],
),
),
);
},
itemCount: teams.length,
),
),
SizedBox(
height: 70,
),
],
),
)
),
);
}
}
class Stats{
String title;
String result;
Stats(this.title,this.result);
}
class Team {
String name;
String image;
String date;
Team(this.name,this.image,this.date);
}
i am trying to find a way to get all results , not just the first index of my api json
Example of nested ListviewBuilder , don't forget to add shrinkWrap inside the listview
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
shrinkWrap: true,
itemCount: teams.length,
itemBuilder: (BuildContext context, int index) {
List<Transfers> transfers = teams[index].transfers;
return ListView.builder(
shrinkWrap: true,
itemCount: transfers.length,
itemBuilder: (BuildContext context, int index) {
return Text(transfers[index].teams.teamIn.name);
},
) ;
},
),
);
}