I have the following code
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter_form_builder/flutter_form_builder.dart';
class MyData {
String title;
String days;
String words;
String rep;
String gender;
var username;
MyData({this.gender, this.title, this.days, this.words, this.rep, this.username,
});
}
class StepperBody extends StatefulWidget {
#override
_StepperBodyState createState() => _StepperBodyState();
}
class _StepperBodyState extends State<StepperBody> {
int currStep = 0;
static var _focusNode = FocusNode();
GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final GlobalKey<FormBuilderState> _fbKey = GlobalKey<FormBuilderState>();
Future<List<String>> _future;
Future<List<String>> _car;
List<GlobalKey<FormState>> formKeys = [
GlobalKey<FormState>(),
GlobalKey<FormState>(),
GlobalKey<FormState>(),
GlobalKey<FormState>()
];
String _key = "786465659081B207EB5BF1EF9AF7552A6";
String _api = "https://10.0.2.2/api/";
Future<void> senddata(List<String> username) async {
final response = await http.post(
_api + "insert_data.php?key=" + _key, body: {
"username": username,
});
var resp = jsonDecode(response.body);
print(resp.toString());
}
Future<List<String>> getData() async {
var url = _api + "get_data.php?key=" + _key;
http.Response response = await http.get(url);
var resp = jsonDecode(response.body);
print(resp.toString());
return resp.map<String>((m) => m['username'] as String).toList();
}
Future<List<String>> getCar() async {
var url = _api + "get_car.php?key=" + _key;
http.Response response = await http.get(url);
var resp = jsonDecode(response.body);
print(resp.toString());
return resp.map<String>((m) => m['plate'] as String).toList();
}
#override
void initState() {
super.initState();
_future = getData();
_car = getCar();
_focusNode.addListener(() {
setState(() {});
print('Has focus: $_focusNode.hasFocus');
});
}
#override
Widget build(BuildContext context) {
void showSnackBarMessage(String message,
[MaterialColor color = Colors.red]) {
Scaffold.of(context).showSnackBar(SnackBar(content: Text(message)));
}
void _submitDetails(List<String> username) {
final FormState formState = _formKey.currentState;
final FormBuilderState fbKeyState = _fbKey.currentState;
/*
_fbKey.currentState.save();
if (_fbKey.currentState.validate()) {
print(_fbKey.currentState.value);
}
*/
if (!fbKeyState.validate()) {
showSnackBarMessage('Please enter correct data');
senddata(username);
} else {
showSnackBarMessage('Saved');
formState.save();
senddata(username);
print("Name: $username");
_fbKey.currentState.save();
if (_fbKey.currentState.validate()) {
print(_fbKey.currentState.value);
}
}
}
return FutureBuilder<List<String>>(
future: Future.wait([_future, _car]),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
final steps = [
Step(
title: const Text('Users'),
//subtitle: const Text('Subtitle'),
isActive: true,
//state: StepState.editing,
state: StepState.indexed,
content: Form(
key: formKeys[0],
child: Column(
children: <Widget>[
FormBuilder(
key: _fbKey,
autovalidate: true,
child: FormBuilderCheckboxList(
decoration:
InputDecoration(labelText: "Languages you know"),
attribute: "languages",
initialValue: ["English"],
options: snapshot.data[0]
.map((languages) => FormBuilderFieldOption(
value: languages, child: Text("$languages")))
.toList(),
),
),
],
),
),
),
Step(
title: const Text('Users'),
//subtitle: const Text('Subtitle'),
isActive: true,
//state: StepState.editing,
state: StepState.indexed,
content: Form(
key: formKeys[1],
child: Column(
children: <Widget>[
FormBuilder(
key: _fbKey,
autovalidate: true,
child: FormBuilderCheckboxList(
decoration:
InputDecoration(labelText: "Cars"),
attribute: "cars",
initialValue: ["BM-WD01"],
options: snapshot.data[1]
.map((car) => FormBuilderFieldOption(
value: car, child: Text("$car")))
.toList(),
),
),
],
),
),
),
];
return Container(
child: Form(
key: _formKey,
child: ListView(children: <Widget>[
Stepper(
steps: steps,
physics: ClampingScrollPhysics(),
type: StepperType.vertical,
currentStep: this.currStep,
onStepContinue: () {
setState(() {
if (formKeys[currStep].currentState.validate()) {
if (currStep < steps.length - 1) {
currStep = currStep + 1;
} else {
currStep = 0;
}
}
// else {
// Scaffold
// .of(context)
// .showSnackBar( SnackBar(content: Text('$currStep')));
// if (currStep == 1) {
// print('First Step');
// print('object' + FocusScope.of(context).toStringDeep());
// }
// }
});
},
controlsBuilder: (BuildContext context,
{VoidCallback onStepContinue, VoidCallback onStepCancel}) {
return Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
//
RaisedButton(
color: Colors.red,
child: Text("Forward",
style: TextStyle(color: Colors.white)),
onPressed: onStepContinue,
),
SizedBox(width: 15,),
RaisedButton(
color: Colors.red,
child: Text(
"Back", style: TextStyle(color: Colors.white)),
onPressed: onStepCancel,
),
],
);
},
onStepCancel: () {
setState(() {
if (currStep > 0) {
currStep = currStep - 1;
} else {
currStep = 0;
}
});
},
onStepTapped: (step) {
setState(() {
currStep = step;
});
},
),
RaisedButton(
child: Text(
'Save',
style: TextStyle(color: Colors.white),
),
onPressed: () {
var submitDetails = _submitDetails;
submitDetails(snapshot.data);
},
color: Colors.lightGreen,
),
]),
));
} else {
return CircularProgressIndicator();
}
}
);
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: "test",),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
MyAppScreenMode createState() => MyAppScreenMode();
}
class MyAppScreenMode extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return new MaterialApp(
theme: new ThemeData(
primarySwatch: Colors.red,
),
home: new Scaffold(
appBar: new AppBar(
title: new Text('Test stepper'),
),
body: new StepperBody(),
));
}
}
I want to display multiple lists from mySQL, the first function _future works fine, but when I replace future: _future to
future: Future.wait([_future, _car]),
I get an
The element type 'Future<List>' can't be assigned to the list
type 'Future'
I have tried lots of other solutions but none of them works to use snapshot.data[0], snapshot.data1 and so on for more queries and data to display from different tables.
Can't get to work with more futurebuilders which would be even easier for each step own, but then I get
Step(
title: const Text('Users'),
//subtitle: const Text('Subtitle'),
isActive: true,
//state: StepState.editing,
state: StepState.indexed,
content: Form(
key: formKeys[0],
child: FutureBuilder<List>(
future: _future,
// ignore: missing_return
builder: (BuildContext context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
Column(
children: <Widget>[
FormBuilder(
key: _fbKey,
autovalidate: true,
child: FormBuilderCheckboxList(
decoration:
InputDecoration(
labelText: "Languages you know"),
attribute: "languages",
initialValue: ["English"],
options: snapshot.data
.map((gender) =>
FormBuilderFieldOption(
value: gender, child: Text("$gender")))
.toList(),
),
),
],
);
}
}
),
),
),
];
Any help would be appreciated.
The working solution for the question. If there is any better way feel free to post :)
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter_form_builder/flutter_form_builder.dart';
class MyData {
String title;
String days;
String words;
String rep;
String gender;
var username;
MyData(
{this.gender, this.title, this.days, this.words, this.rep, this.username,
});
}
class StepperBody extends StatefulWidget {
#override
_StepperBodyState createState() => _StepperBodyState();
}
class _StepperBodyState extends State<StepperBody> {
int currStep = 0;
static var _focusNode = FocusNode();
GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final GlobalKey<FormBuilderState> _fbKey = GlobalKey<FormBuilderState>();
Future<List<String>> _future;
Future<List<String>> _getcar;
List<GlobalKey<FormState>> formKeys = [
GlobalKey<FormState>(),
GlobalKey<FormState>(),
GlobalKey<FormState>(),
GlobalKey<FormState>()
];
String _key = "786465659081B207EB5BF1EF9AF7552A6";
String _api = "https://10.0.2.2/api/";
Future<void> senddata() async {
final response = await http.post(
_api + "insert_data.php?key=" + _key, body: {
});
var resp = jsonDecode(response.body);
print(resp.toString());
}
Future<List<String>> getData() async {
var url = _api + "get_data.php?key=" + _key;
http.Response response = await http.get(url);
var resp = jsonDecode(response.body);
print(resp.toString());
return resp.map<String>((m) => m['username'] as String).toList();
}
Future<List<String>> getCar() async {
var url = _api + "get_car.php?key=" + _key;
http.Response response = await http.get(url);
var resp = jsonDecode(response.body);
print(resp.toString());
return resp.map<String>((m) => m['plate'] as String).toList();
}
Widget getdis2(BuildContext context) {
return FutureBuilder<List<String>>(
future: _getcar, // a previously-obtained Future<String> or null
builder: (BuildContext context, AsyncSnapshot<List<String>> snapshot) {
List<Widget> children;
if (snapshot.hasData) {
children = <Widget>[
FormBuilderCheckboxList(
decoration:
InputDecoration(
labelText: "Languages you know"),
attribute: "languages",
initialValue: ["English"],
options: snapshot.data
.map((gender) =>
FormBuilderFieldOption(
value: gender, child: Text("$gender")))
.toList(),
),
];
} else if (snapshot.hasError) {
children = <Widget>[
Icon(
Icons.error_outline,
color: Colors.red,
size: 60,
),
Padding(
padding: const EdgeInsets.only(top: 16),
child: Text('Error: ${snapshot.error}'),
)
];
} else {
children = <Widget>[
SizedBox(
child: CircularProgressIndicator(),
width: 60,
height: 60,
),
const Padding(
padding: EdgeInsets.only(top: 16),
child: Text('Awaiting result...'),
)
];
}
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: children,
),
);
},
);
}
Widget getdis(BuildContext context) {
return FutureBuilder<List<String>>(
future: _future, // a previously-obtained Future<String> or null
builder: (BuildContext context, AsyncSnapshot<List<String>> snapshot) {
List<Widget> children;
if (snapshot.hasData) {
children = <Widget>[
FormBuilderCheckboxList(
decoration:
InputDecoration(
labelText: "Languages you know"),
attribute: "languages",
initialValue: ["English"],
options: snapshot.data
.map((gender) =>
FormBuilderFieldOption(
value: gender, child: Text("$gender")))
.toList(),
),
];
} else if (snapshot.hasError) {
children = <Widget>[
Icon(
Icons.error_outline,
color: Colors.red,
size: 60,
),
Padding(
padding: const EdgeInsets.only(top: 16),
child: Text('Error: ${snapshot.error}'),
)
];
} else {
children = <Widget>[
SizedBox(
child: CircularProgressIndicator(),
width: 60,
height: 60,
),
const Padding(
padding: EdgeInsets.only(top: 16),
child: Text('Awaiting result...'),
)
];
}
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: children,
),
);
},
);
}
#override
void initState() {
super.initState();
_future = getData();
_getcar = getCar();
_focusNode.addListener(() {
setState(() {});
print('Has focus: $_focusNode.hasFocus');
});
}
#override
Widget build(BuildContext context) {
void showSnackBarMessage(String message,
[MaterialColor color = Colors.red]) {
Scaffold.of(context).showSnackBar(SnackBar(content: Text(message)));
}
void _submitDetails() {
final FormState formState = _formKey.currentState;
final FormBuilderState fbKeyState = _fbKey.currentState;
/*
_fbKey.currentState.save();
if (_fbKey.currentState.validate()) {
print(_fbKey.currentState.value);
}
*/
if (!fbKeyState.validate()) {
showSnackBarMessage('Please enter correct data');
senddata();
} else {
showSnackBarMessage('Saved');
formState.save();
senddata();
print("Name: ");
_fbKey.currentState.save();
if (_fbKey.currentState.validate()) {
print(_fbKey.currentState.value);
}
}
}
final steps = [
Step(
title: const Text('Users'),
//subtitle: const Text('Subtitle'),
isActive: true,
//state: StepState.editing,
state: StepState.indexed,
content: Form(
key: formKeys[0],
child: getdis(context),
),
),
Step(
title: const Text('Cars'),
//subtitle: const Text('Subtitle'),
isActive: true,
//state: StepState.editing,
state: StepState.indexed,
content: Form(
key: formKeys[1],
child: getdis2(context),
),
),
];
return Container(
child: Form(
key: _formKey,
child: ListView(children: <Widget>[
Stepper(
steps: steps,
physics: ClampingScrollPhysics(),
type: StepperType.vertical,
currentStep: this.currStep,
onStepContinue: () {
setState(() {
if (formKeys[currStep].currentState.validate()) {
if (currStep < steps.length - 1) {
currStep = currStep + 1;
} else {
currStep = 0;
}
}
// else {
// Scaffold
// .of(context)
// .showSnackBar( SnackBar(content: Text('$currStep')));
// if (currStep == 1) {
// print('First Step');
// print('object' + FocusScope.of(context).toStringDeep());
// }
// }
});
},
controlsBuilder: (BuildContext context,
{VoidCallback onStepContinue, VoidCallback onStepCancel}) {
return Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
//
RaisedButton(
color: Colors.red,
child: Text("Forward",
style: TextStyle(color: Colors.white)),
onPressed: onStepContinue,
),
SizedBox(width: 15,),
RaisedButton(
color: Colors.red,
child: Text(
"Back", style: TextStyle(color: Colors.white)),
onPressed: onStepCancel,
),
],
);
},
onStepCancel: () {
setState(() {
if (currStep > 0) {
currStep = currStep - 1;
} else {
currStep = 0;
}
});
},
onStepTapped: (step) {
setState(() {
currStep = step;
});
},
),
RaisedButton(
child: Text(
'Save',
style: TextStyle(color: Colors.white),
),
onPressed: () {
var submitDetails = _submitDetails;
submitDetails();
},
color: Colors.lightGreen,
),
]),
));
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: "test",),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
MyAppScreenMode createState() => MyAppScreenMode();
}
class MyAppScreenMode extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return new MaterialApp(
theme: new ThemeData(
primarySwatch: Colors.red,
),
home: new Scaffold(
appBar: new AppBar(
title: new Text('Test stepper'),
),
body: new StepperBody(),
));
}
}
Im not sure about this, but in my understanding, a FutureBuilder expects exactly 1 future. the returned value of this future is accessable with "snapshot.data".
If you need to wait for multiple futures to resolve, I propose you use multiple FutureBuilders.
Another way would be to use Future.wait() somewhere else and return all required data as one Furure from there.
Related
Flutter
I want to change the end of the url in my project, I used SearchDelegate for this, but I can't change it, my codes are as follows
Search code
enter code here
class Arama extends SearchDelegate {
Future<List<Model>>? apilistfuture;
#override
List<Widget>? buildActions(BuildContext context) {
return [
IconButton(
onPressed: () {
query = '';
},
icon: const Icon(
Icons.close,
color: Colors.red,
),
),
];
}
#override
Widget? buildLeading(BuildContext context) {
return IconButton(
onPressed: () {
Navigator.pop(context);
},
icon: const Icon(
Icons.arrow_back_ios,
color: Colors.black,
),
);
}
#override
Widget buildResults(BuildContext context) {
return FutureBuilder<List<Model>>(
future: apilistfuture,
builder: (context, snapshot) {
if (snapshot.hasData) {
List<Model> _listem = snapshot.data!;
return ListView.builder(
itemCount: _listem.length,
itemBuilder: (context, index) {
var oankiApi = _listem[index];
return ListTile(
title: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Tanım: ${oankiApi.description}'),
Text('Ekran Senbol: ${oankiApi.displaySymbol}'),
Text('Senbol: ${oankiApi.symbol}'),
Text('Tip: ${oankiApi.type}'),
],
),
);
},
);
} else if (snapshot.hasError) {
return const Center(
child: Text('hata'),
);
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
},
);
}
#override
Widget buildSuggestions(BuildContext context) {
return const Center(
child: Text(
'Arama..',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
);
}
}
home code
class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
#override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
Future<List<Model>>? apilistfuture;
#override
void initState() {
apilistfuture = Api.getapiData();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
onPressed: () {
showSearch(context: context, delegate: Arama());
},
icon: const Icon(Icons.search),
),
],
backgroundColor: Colors.blue,
),
body: FutureBuilder<List<Model>>(
future: apilistfuture,
builder: (context, snapshot) {
if (snapshot.hasData) {
List<Model> _listem = snapshot.data!;
return ListView.builder(
itemCount: _listem.length,
itemBuilder: (context, index) {
var oankiApi = _listem[index];
return ListTile(
title: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Tanım: ${oankiApi.description}'),
Text('Ekran Senbol: ${oankiApi.displaySymbol}'),
Text('Senbol: ${oankiApi.symbol}'),
Text('Tip: ${oankiApi.type}'),
],
),
);
},
);
} else if (snapshot.hasError) {
return const Center(
child: Text('hata'),
);
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
},
),
);
}
}
In the project, expressions such as string, int will come to the place where the value is written at the end of the url, how can I bring the value?
api code
class Api {
static Future<List<Model>> getapiData({String? deger}) async {
String url = 'http://10.0.2.2:5000/symbol_lookup?search=${deger}';
List<Model> list = [];
var result = await Dio().get(url);
var apiList = jsonDecode(result.data)['result'];
if (apiList is List) {
list = apiList.map((e) => Model.fromJson(e)).toList();
//sonradan eklendi
if (deger != null) {
list = list
.where((element) => element.description!
.toLowerCase()
.contains(deger.toLowerCase()))
.toList();
}
} else {
return [];
}
debugPrint(list.length.toString());
return list;
}
}
Int, string texts will be followed by an equal sign at the end of the url, for example, values such as 'https://login=search' will come. Could you help me find the problem? I tried a few things but it comes up blank
enter image description here
enter image description here
As you can see in the pictures, I get an error when I call.
I made a simple store app where I put data in a json file. I've managed to call the data into the Tabbar & TabbarView by FutureBuilder. Also I put the list of these products in a drawer. I want if I click on one of the product names from Drawer, it will navigate to specific TabBar respective IDs.
I've done this trick before, but only on static pages, not FutureBuilder like this. I really appreciate any help
HomePage.dart
import 'dart:convert';
import 'package:contoh_tabbar_json/model.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class HomePage extends StatefulWidget {
const HomePage({Key key}) : super(key: key);
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> with SingleTickerProviderStateMixin {
Future<List<Product>> _getProduct() async {
final dataString = await rootBundle.loadString('assets/myproduct.json');
final List<dynamic> json = jsonDecode(dataString);
final products = <Product>[];
for (var v in json) {
products.add(Product.fromJson(v));
}
return products;
}
#override
void initState() {
_getProduct();
super.initState();
}
#override
void dispose() {
super.dispose();
}
Product product;
#override
Widget build(BuildContext context) {
return FutureBuilder<List<Product>>(
future: _getProduct(),
builder: (context, mydata) {
if (mydata.hasData) {
List<Tab> tabs = <Tab>[];
for (int index = 0; index < mydata.data.length; index++) {
tabs.add(Tab(
child: Text(
mydata.data[index].title,
),
));
}
return DefaultTabController(
length: mydata.data.length,
child: Scaffold(
endDrawer: Drawer(
child: SingleChildScrollView(
physics: const ScrollPhysics(),
child: Column(
children: [
Center(
child: Container(
height: 100,
alignment: Alignment.center,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 5),
decoration: const BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(50),
),
),
child: const Text("Product List",
style: TextStyle(
fontSize: 17,
fontWeight: FontWeight.w700,
),
textAlign: TextAlign.center),
),
),
),
//
ListView.builder(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: mydata.data.length,
itemBuilder: (BuildContext context, index) {
return ListTile(
dense: true,
title: Text(mydata.data[index].title, style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w500)),
onTap: () {
Navigator.pop(context);
},
);
}),
const SizedBox(height: 70),
],
),
),
),
appBar: AppBar(
title: const Text("My Store"),
bottom: TabBar(
isScrollable: true,
tabs: tabs,
),
),
body: FutureBuilder<List<Product>>(
future: _getProduct(),
builder: (context, mydata) {
if (mydata.hasData) {
List<Widget> tabs = <Widget>[];
for (int index = 0; index < mydata.data.length; index++) {
tabs.add(Tab(
child: SingleChildScrollView(
physics: const BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
const SizedBox(height: 30),
Text(
mydata.data[index].title,
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
const SizedBox(height: 30),
Text(mydata.data[index].title),
const SizedBox(height: 30),
Text(mydata.data[index].description),
const SizedBox(height: 30),
Text(mydata.data[index].category),
],
),
),
),
));
}
return TabBarView(
children: tabs,
);
}
return Container();
},
),
),
);
}
return Scaffold(
body: Center(child: Text(mydata.hasError ? mydata.error.toString() : "Loading...")),
);
},
);
}
}
Model
import 'dart:convert';
List<Product> productFromJson(String str) =>
List<Product>.from(json.decode(str).map((x) => Product.fromJson(x)));
class Product {
Product({
this.id,
this.title,
this.description,
this.category,
});
final int id;
final String title;
final String description;
final String category;
factory Product.fromJson(Map<String, dynamic> json) => Product(
id: json["id"],
title: json["title"],
description: json["description"],
category: json["category"],
);
String getTitle() {
return title;
}
String getDescription() {
return description;
}
String getCategory() {
return category;
}
}
Mungkin bisa dicek pada github saya :
https://github.com/kuldii/navigate_drawer_tabbar
this is my first flutter JSON example, I tried to fetch data from the JSON link and display it on a drop-down list.
I am getting the response on the console but the drop-down list doesn't work
any help, please?......................................................................................................................................................................................................................................................................................................................
this is the body
ERROR
this is my code
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
void initState() {
_getfamilyList();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Container(
padding: EdgeInsets.only(left: 15, right: 15, top: 5),
color: Colors.white,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Expanded(
child: DropdownButtonHideUnderline(
child: ButtonTheme(
alignedDropdown: true,
child: DropdownButton<String>(
value: _myfamily,
iconSize: 30,
icon: (null),
style: TextStyle(
color: Colors.black54,
fontSize: 16,
),
hint: Text('Select family'),
onChanged: (String newValue) {
setState(() {
_myfamily = newValue;
print(_myfamily);
});
},
items: familysList?.map((item) {
return new DropdownMenuItem(
child: new Text(item['firsName']),
);
})?.toList() ??
[],
),
),
),
),
],
),
),
],
),
);
}
List familysList;
String _myfamily;
String familyInfoUrl =
'http://10.0.2.2:3000/genocheck/user/getmembrefamille/f1';
Future<String> _getfamilyList() async {
await http.get(familyInfoUrl).then((response) {
var data = json.decode(response.body);
print(data);
setState(() {
familysList = data['famille'];
});
});
}
}
as I see the problem is in your JSON response
famille is the first element ,
the list of data is the second element
however in your code familysList = data['famille'];
you are assuming that famille is a key and the list of data is the value and this is not correct
so answer is one of those
1 - make your asignment like familysList = data[0];
2- change your json to be {"famille" :[{"id":8654,"firstname":"some name"]"}
The error caused because although data's type is List that can access by 'int' index, you access like Map.
data['famille']
As your data body, data[0] is 'famille' and data[1] is data what you want.
data[1] is
[
{
"_id": "",
"firstName": "",
}
]
You can copy paste run full code below
Step 1: data[0] is String famille, data[1] is List you want
familysList = data[1];
Step 2: firsName is typo you need firstName
Step 3: DropdownMenuItem need value attribute
items: familysList?.map((item) {
return DropdownMenuItem<String>(
child: Text("${item["firstName"]}"),
value: item["firstName"],
);
})?.toList() ??
working demo
full code
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
void initState() {
_getfamilyList();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Container(
padding: EdgeInsets.only(left: 15, right: 15, top: 5),
color: Colors.white,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Expanded(
child: DropdownButtonHideUnderline(
child: ButtonTheme(
alignedDropdown: true,
child: DropdownButton<String>(
value: _myfamily,
iconSize: 30,
icon: (null),
style: TextStyle(
color: Colors.black54,
fontSize: 16,
),
hint: Text('Select family'),
onChanged: (String Value) {
setState(() {
_myfamily = Value;
print("_myfamily $_myfamily");
});
},
items: familysList?.map((item) {
//print(item["firstName"]);
return DropdownMenuItem<String>(
child: Text("${item["firstName"]}"),
value: item["firstName"],
);
})?.toList() ??
[],
),
),
),
),
],
),
),
],
),
);
}
List familysList;
String _myfamily;
String familyInfoUrl =
'http://10.0.2.2:3000/genocheck/user/getmembrefamille/f1';
Future<String> _getfamilyList() async {
String jsonString = '''
[
"famille",
[
{
"_id" : "123",
"firstName":"abc"
},
{
"_id" : "456",
"firstName":"def"
}
]
]
''';
http.Response response = http.Response(jsonString, 200);
var data = json.decode(response.body);
print(data);
setState(() {
familysList = data[1];
});
/*await http.get(familyInfoUrl).then((response) {
var data = json.decode(response.body);
print(data);
setState(() {
familysList = data[1];
});
});*/
}
}
full code 2 for new question
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
class UserElement {
UserElement({
this.id,
this.firstName,
});
String id;
String firstName;
factory UserElement.fromJson(Map<String, dynamic> json) => UserElement(
id: json["_id"] == null ? null : json["_id"],
firstName: json["firstName"] == null ? null : json["firstName"],
);
Map<String, dynamic> toJson() => {
"_id": id == null ? null : id,
"firstName": firstName == null ? null : firstName,
};
}
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
void initState() {
_getfamilyList();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Container(
padding: EdgeInsets.only(left: 15, right: 15, top: 5),
color: Colors.white,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Expanded(
child: DropdownButtonHideUnderline(
child: ButtonTheme(
alignedDropdown: true,
child: DropdownButton<UserElement>(
value: _myfamily,
iconSize: 30,
icon: (null),
style: TextStyle(
color: Colors.black54,
fontSize: 16,
),
hint: Text('Select family'),
onChanged: (UserElement Value) {
setState(() {
_myfamily = Value;
print("_myfamily ${_myfamily.firstName}");
});
},
items: familysList?.map((item) {
return DropdownMenuItem<UserElement>(
child: Text("${item.id} ${item.firstName}"),
value: item,
);
})?.toList() ??
[],
),
),
),
),
],
),
),
],
),
);
}
List<UserElement> familysList = [];
UserElement _myfamily;
String familyInfoUrl =
'http://10.0.2.2:3000/genocheck/user/getmembrefamille/f1';
Future<String> _getfamilyList() async {
String jsonString = '''
[
"famille",
[
{
"_id" : "123",
"firstName":"abc"
},
{
"_id" : "456",
"firstName":"abc"
}
]
]
''';
http.Response response = http.Response(jsonString, 200);
var data = json.decode(response.body);
//print(data);
setState(() {
List<dynamic> listData = data[1];
for (var i = 0; i < listData.length; i++) {
familysList.add(UserElement.fromJson(listData[i]));
}
});
/*await http.get(familyInfoUrl).then((response) {
var data = json.decode(response.body);
print(data);
setState(() {
familysList = data['famille'];
});
});*/
}
}
My Json response status code is 200 and the object is also created but when I try to bind it with UI in ListView it doesn't show anything. I have used quicktype.io to parse my json data that I received from the API call.
Here's my API_manager.dart file:
import 'package:http/http.dart' as http;
import 'package:aritic/models/contactsModel.dart';
// ignore: camel_case_types
class API_Manager {
Future<ContactsModel> getContacts() async {
var client = http.Client();
var contactsModel;
String contacts_url =
'https://exampleapi.com';
String basicAuth = 'Basic auth key example';
try {
var response = await client.get(contacts_url,
headers: <String, String>{'authorization': basicAuth});
print(response.statusCode);
if (response.statusCode == 200) {
var jsonString = response.body;
var jsonMap = json.decode(jsonString);
contactsModel = contactsModel.fromJson(jsonMap);
}
} catch (Exception) {
return contactsModel;
}
return contactsModel;
}
}
My UI code:
import 'package:aritic/models/contactsModel.dart';
import 'package:aritic/services/api_manager.dart';
class ContactsPage extends StatefulWidget {
#override
_ContactsPageState createState() => _ContactsPageState();
}
class _ContactsPageState extends State<ContactsPage>
with SingleTickerProviderStateMixin {
Future<ContactsModel> _contactsModel;
bool isSearching = false;
TabController _tabController;
#override
void initState() {
// TODO: implement initState
super.initState();
_tabController = TabController(length: 2, initialIndex: 0, vsync: this);
_tabController.addListener(_handleTabIndex);
}
#override
void dispose() {
_tabController.removeListener(_handleTabIndex);
_tabController.dispose();
super.dispose();
}
void _handleTabIndex() {
setState(() {});
}
#override
Widget build(BuildContext context) {
_contactsModel = API_Manager().getContacts();
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
title: Text('Contacts'),
bottom: PreferredSize(
child: Align(
alignment: Alignment.centerLeft,
child: TabBar(
controller: _tabController,
isScrollable: true,
unselectedLabelColor: Colors.white.withOpacity(0.3),
indicatorColor: Colors.white,
tabs: [
Tab(
child: Text('Contacts'),
),
Tab(
child: Text('Companies'),
)
],
),
),
preferredSize: Size.fromHeight(40.0)),
actions: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 16.0),
child: IconButton(
icon: Icon(Icons.search),
color: Colors.white,
onPressed: () {},
),
),
],
),
body: TabBarView(controller: _tabController, children: <Widget>[
Container(
height: double.infinity,
child: FutureBuilder<ContactsModel>(
future: _contactsModel,
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
padding: const EdgeInsets.all(6),
itemCount: snapshot.data.contacts.length,
itemBuilder: (context, index) {
var contact = snapshot.data.contacts[index];
return Container(
height: 100,
color: Colors.white,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(contact.owner.username,
style: TextStyle(fontSize: 16))
],
),
);
});
} else
return Center(child: CircularProgressIndicator());
})),
Container(
height: double.infinity,
child: ListView(
padding: const EdgeInsets.all(6),
children: <Widget>[
InkWell(
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (_) => ViewCompany()));
},
child: Container(
height: 50,
color: Colors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Example company',
style: TextStyle(fontSize: 16),
),
Text(
'Example company',
style: TextStyle(fontSize: 14),
)
],
),
),
),
SizedBox(
height: 5,
),
InkWell(
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (_) => ViewCompany()));
},
child: Container(
height: 50,
color: Colors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'example',
style: TextStyle(fontSize: 16),
),
Text(
'example',
style: TextStyle(fontSize: 14),
)
],
),
),
),
],
)),
]),
floatingActionButton: _bottomButtons(),
));
}
Widget _bottomButtons() {
return _tabController.index == 0
? FloatingActionButton(
shape: StadiumBorder(),
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (_) {
return AddContacts();
}));
},
backgroundColor: Colors.cyan,
child: Icon(
Icons.person_add,
color: Colors.white,
))
: FloatingActionButton(
shape: StadiumBorder(),
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (_) {
return AddCompany();
}));
},
backgroundColor: Colors.cyan,
child: Icon(
Icons.add,
color: Colors.white,
),
);
}
}
Created model(contactsModel.dart):
import 'dart:convert';
ContactsModel contactsModelFromJson(String str) => ContactsModel.fromJson(json.decode(str));
String contactsModelToJson(ContactsModel data) => json.encode(data.toJson());
class ContactsModel {
ContactsModel({
this.total,
this.contacts,
});
String total;
Map<String, Contact> contacts;
factory ContactsModel.fromJson(Map<String, dynamic> json) => ContactsModel(
total: json["total"],
contacts: Map.from(json["contacts"]).map((k, v) => MapEntry<String, Contact>(k, Contact.fromJson(v))),
);
Map<String, dynamic> toJson() => {
"total": total,
"contacts": Map.from(contacts).map((k, v) => MapEntry<String, dynamic>(k, v.toJson())),
};
}
class Contact {
Contact({
this.isPublished,
this.dateAdded,
this.dateModified,
this.createdBy,
this.createdByUser,
this.modifiedBy,
this.modifiedByUser,
this.id,
this.points,
this.color,
this.fields,
this.lastActive,
this.owner,
this.ipAddresses,
this.tags,
this.utmtags,
this.stage,
this.dateIdentified,
this.preferredProfileImage,
this.doNotContact,
this.frequencyRules,
});
bool isPublished;
DateTime dateAdded;
DateTime dateModified;
int createdBy;
String createdByUser;
int modifiedBy;
String modifiedByUser;
int id;
int points;
dynamic color;
Fields fields;
dynamic lastActive;
Owner owner;
List<dynamic> ipAddresses;
List<Tag> tags;
List<dynamic> utmtags;
Stage stage;
DateTime dateIdentified;
dynamic preferredProfileImage;
List<dynamic> doNotContact;
List<dynamic> frequencyRules;
factory Contact.fromJson(Map<String, dynamic> json) => Contact(
isPublished: json["isPublished"],
dateAdded: DateTime.parse(json["dateAdded"]),
dateModified: json["dateModified"] == null ? null : DateTime.parse(json["dateModified"]),
createdBy: json["createdBy"],
createdByUser: json["createdByUser"],
modifiedBy: json["modifiedBy"] == null ? null : json["modifiedBy"],
modifiedByUser: json["modifiedByUser"] == null ? null : json["modifiedByUser"],
id: json["id"],
points: json["points"],
color: json["color"],
fields: Fields.fromJson(json["fields"]),
lastActive: json["lastActive"],
owner: Owner.fromJson(json["owner"]),
ipAddresses: List<dynamic>.from(json["ipAddresses"].map((x) => x)),
tags: List<Tag>.from(json["tags"].map((x) => Tag.fromJson(x))),
utmtags: List<dynamic>.from(json["utmtags"].map((x) => x)),
stage: Stage.fromJson(json["stage"]),
dateIdentified: DateTime.parse(json["dateIdentified"]),
preferredProfileImage: json["preferredProfileImage"],
doNotContact: List<dynamic>.from(json["doNotContact"].map((x) => x)),
frequencyRules: List<dynamic>.from(json["frequencyRules"].map((x) => x)),
);
Map<String, dynamic> toJson() => {
"isPublished": isPublished,
"dateAdded": dateAdded.toIso8601String(),
"dateModified": dateModified == null ? null : dateModified.toIso8601String(),
"createdBy": createdBy,
"createdByUser": createdByUser,
"modifiedBy": modifiedBy == null ? null : modifiedBy,
"modifiedByUser": modifiedByUser == null ? null : modifiedByUser,
"id": id,
"points": points,
"color": color,
"fields": fields.toJson(),
"lastActive": lastActive,
"owner": owner.toJson(),
"ipAddresses": List<dynamic>.from(ipAddresses.map((x) => x)),
"tags": List<dynamic>.from(tags.map((x) => x.toJson())),
"utmtags": List<dynamic>.from(utmtags.map((x) => x)),
"stage": stage.toJson(),
"dateIdentified": dateIdentified.toIso8601String(),
"preferredProfileImage": preferredProfileImage,
"doNotContact": List<dynamic>.from(doNotContact.map((x) => x)),
"frequencyRules": List<dynamic>.from(frequencyRules.map((x) => x)),
};
}
class ......{}
Output Screen: here
Json Viewer: here
Dart Devtools: here
This is probably not a problem with your json parsing, but a UI issue. Putting Columns or Rows inside ListViews or the opposite. If there was something wrong with the json, you'd be seeing the return Center(child: CircularProgressIndicator());,
But instead, you're getting an empty UI.
Check your debug console, if you have RenderView errors, or failed to layout render-box issues, this will be the cause of them.
Try using the property of shrink wrap in your lists:
ListView(shrinkwrap:true...
and
ListView.builder(shirinkrap:true...
Also, wrap your Row that inside the ListView with a LimitedBox
i.e
LimitedBox(
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
I have created a PickImages class which can takes images both from camera and gallery like below. Now I want to post the images as base64 string to a json api server.
Here is PickImages class.
import 'dart:convert';
import 'dart:developer';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
//import 'services/services.dart';
class PickImages extends StatefulWidget {
#override
_PickImagesState createState() => _PickImagesState();
}
class _PickImagesState extends State<PickImages> {
List<Object> images = List<Object>();
Future<File> _imageFile;
bool _isVisible = false;
Future _onAddImageClick(int index, int type) async {
if (images != null)
setState(() {
// ignore: deprecated_member_use
_imageFile = ImagePicker.pickImage(
source: type == 1 ? ImageSource.camera : ImageSource.gallery,
imageQuality: 50,
);
getFileImage(index);
});
}
void getFileImage(int index) async {
_imageFile.then((file) async {
setState(() {
ImageUploadModel imageUpload = new ImageUploadModel();
imageUpload.imageFile = file;
images.replaceRange(index, index + 1, [imageUpload]);
});
});
}
void showImageBox() {
setState(() {
_isVisible = !_isVisible;
});
}
#override
void initState() {
super.initState();
setState(() {
images.add("Add Image");
images.add("Add Image");
images.add("Add Image");
images.add("Add Image");
images.add("Add Image");
images.add("Add Image");
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Post Images'),
),
body: Column(
children: <Widget>[
Container(
//padding: EdgeInsets.only(right: 5),
child: Card(
elevation: 5,
child: ListTile(
trailing: Icon(Icons.attachment),
title: Text('Attachments'),
onTap: () {
showImageBox();
},
),
),
),
Visibility(
visible: _isVisible,
child: Padding(
padding: const EdgeInsets.only(top: 5.0, right: 5.0),
child: GridView.count(
shrinkWrap: true,
crossAxisCount: 3,
childAspectRatio: 1,
children: List.generate(images.length, (index) {
if (images[index] is ImageUploadModel) {
ImageUploadModel uploadModel = images[index];
//base64 image
List<int> imageBytes =
uploadModel.imageFile.readAsBytesSync();
String base64Image = base64Encode(
imageBytes); //'base64Image' holds the base64 image string
return Card(
clipBehavior: Clip.antiAlias,
child: Stack(
children: <Widget>[
Image.file(
uploadModel.imageFile,
fit: BoxFit.cover,
width: 300,
height: 300,
),
Positioned(
right: 5,
top: 5,
child: InkWell(
child: Icon(
Icons.remove_circle,
size: 20,
color: Colors.red,
),
onTap: () {
setState(() {
images.replaceRange(
index, index + 1, ['Add Image']);
});
},
),
),
RaisedButton(
child: Text('imgInfo'),
onPressed: () {
print(
"${uploadModel.imageFile.lengthSync() / 1024} KB"); //print image size in kb
print(uploadModel
.imageFile.path); //print image path
log(base64Image);
},
),
],
),
);
} else {
return Card(
child: IconButton(
icon: Icon(Icons.camera_alt),
onPressed: () {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return SafeArea(
child: Container(
child: new Wrap(
children: <Widget>[
new ListTile(
leading: new Icon(Icons.photo_camera),
title: new Text('Camera'),
onTap: () {
_onAddImageClick(index, 1);
Navigator.of(context).pop();
},
),
new ListTile(
leading:
new Icon(Icons.photo_library),
title: new Text('Gallery'),
onTap: () {
_onAddImageClick(index, 2);
Navigator.of(context).pop();
}),
],
),
),
);
},
);
},
),
);
}
}),
),
),
),
RaisedButton(
child: Text('send'),
onPressed: () {
//postImage(base64Image);
},
),
],
),
);
}
}
class ImageUploadModel {
File imageFile;
ImageUploadModel({
this.imageFile,
});
}
Here is ImageModel.
class ImageModel {
String attachment;
ImageModel({this.attachment});
ImageModel.fromJson(Map<String, dynamic> json) {
attachment = json['Attachment'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['Attachment'] = this.attachment;
return data;
}
}
Here is services.dart where in "Attatchment" : " " I have to sent the base64 images string.
import 'dart:convert';
import 'dart:async';
import 'package:http/http.dart' as http;
import 'package:post_image/model/model.dart';
Future<ImageModel> postImage() async {
Map data = {
"Attachment": ""
};
var body = json.encode(data);
final http.Response response = await http.post(
'url',
body: body,
);
print(response.body);
print(body);
if (response.statusCode == 200) {
return ImageModel.fromJson(
jsonDecode(response.body),
);
} else {
throw Exception('Failed to send');
}
}
You can follow this guide on sending data in Flutter using http.post(). To send a List<ImageModel>, you just need to encode it using json.encode() when passing it in the body of your http.post request.