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
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.
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.
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.
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());
}
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);
},
) ;
},
),
);
}