Related
I receive this exception as thrown in the line ShowChart(data: dataapi.data) although i define it as a list below. I also tried to map my List data but no solution.
I am new to flutter, sorry if this is a dummy question.
The exception thrown :
════════ Exception caught by widgets library ═══════════════════════════════════
type 'List<Series<Hakedis, dynamic>>' is not a subtype of type 'List<Series<dynamic, num>>'
The relevant error-causing widget was
ShowChart
lib/screens/pageThree.dart:49
════════════════════════════════════════════════════════════════════════════════
The code:
// MAIN WIDGET
class PageThree extends StatefulWidget {
final String url;
const PageThree({this.url});
#override
_PageThreeState createState() => _PageThreeState();
}
class _PageThreeState extends State<PageThree> {
var chart;
Future<List<Hakedis>> getChartData(widget) async {
final jsonEndpoint = "https://securityconcern.php";
final response = await get(jsonEndpoint);
final List<dynamic> jsonData = jsonDecode(response.body);
return jsonData.map((data) => Hakedis.fromJson(data)).toList();
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: Text('GraphTest'),
),
body: Padding(
padding: EdgeInsets.all(8.0),
child: FutureBuilder<List>(
future: getChartData(widget),
builder: (context, dataapi) {
if (dataapi.hasError) print(dataapi.error);
return dataapi.hasData
? ShowChart(data: dataapi.data)
: Center(child: CircularProgressIndicator());
},
),
),
),
);
}
}
// CHART
class ShowChart extends StatelessWidget {
final List<Hakedis> data;
ShowChart({this.data});
static List<charts.Series<Hakedis, dynamic>> _createSampleData(dataAPI) {
return [
new charts.Series<Hakedis, dynamic>(
id: 'dis adet',
colorFn: (_, __) => charts.MaterialPalette.blue.shadeDefault,
areaColorFn: (_, __) =>
charts.MaterialPalette.blue.shadeDefault.lighter,
//x-axis
domainFn: (Hakedis hakedis, _) => hakedis.tarih,
//y-axis
measureFn: (Hakedis hakedis, _) => double.tryParse(hakedis.disadet).round(),
data: dataAPI,
)
];
}
#override
Widget build(BuildContext context) {
return Container(
child: charts.LineChart(
_createSampleData(data),
defaultRenderer:
new charts.LineRendererConfig(includeArea: true, stacked: true),
animate: true,
domainAxis: charts.NumericAxisSpec(
tickProviderSpec:
charts.BasicNumericTickProviderSpec(zeroBound: false),
),
),
);
}
}
/////////////////////////////////////
class Hakedis {
Hakedis({
this.id,
this.tarih,
this.disadet,
});
final int id;
String disadet;
DateTime tarih;
factory Hakedis.fromJson(Map<String, dynamic> jsonData) => Hakedis(
id: jsonData['id'],
tarih: jsonData['tarih'],
disadet: jsonData['disadet'],
);
Map<String, dynamic> toJson() => {
"id": id,
"tarih": tarih,
"disadet": disadet,
};
}
The data i am parsing via API;
(here is the "tarih" column gets month name as date, and i am trying to convert into datetime format)
[{"santiye1":"TSK_Ankara","tarih":"August","disadet":"1252"},{"santiye1":"TSK_Ankara","tarih":"September","disadet":"6528"},{"santiye1":"KMO_Istanbul","tarih":"August","disadet":"4382"},{"santiye1":"KMO_Istanbul","tarih":"September","disadet":"3317"},{"santiye1":"izmit","tarih":"January","disadet":"400"},{"santiye1":"izmit","tarih":"February","disadet":"7883"},{"santiye1":"izmit","tarih":"March","disadet":"9601"},{"santiye1":"izmit","tarih":"April","disadet":"25692"},{"santiye1":"izmit","tarih":"May","disadet":"15714"},{"santiye1":"izmit","tarih":"June","disadet":"28024"},{"santiye1":"izmit","tarih":"July","disadet":"18179"},{"santiye1":"izmit","tarih":"December","disadet":"3612"},{"santiye1":"Akkuyu1","tarih":"April","disadet":"10981"},{"santiye1":"Akkuyu1","tarih":"May","disadet":"4384"},{"santiye1":"Akkuyu1","tarih":"June","disadet":"8330"},{"santiye1":"Akkuyu1","tarih":"July","disadet":"5037"},{"santiye1":"Akkuyu1","tarih":"August","disadet":"6730"},{"santiye1":"Akkuyu1","tarih":"September","disadet":"3523"}]
From the data that you provided I have created a example
import 'package:dio_json_parsing/model.dart';
import 'package:flutter/material.dart';
import 'package:charts_flutter/flutter.dart' as charts;
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: PageThree(),
);
}
}
class PageThree extends StatefulWidget {
final String url;
const PageThree({this.url});
#override
_PageThreeState createState() => _PageThreeState();
}
class _PageThreeState extends State<PageThree> {
var chart;
Future<List<Hakedis>> getChartData(widget) async {
//final jsonEndpoint = "https://securityconcern.php";
//final response = await get(jsonEndpoint);
// Above where you fetch the data
final List<dynamic> data = dataFromJson(jsonString);
return data;
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: Text('GraphTest'),
),
body: Padding(
padding: EdgeInsets.all(8.0),
child: FutureBuilder<List>(
future: getChartData(widget),
builder: (context, dataapi) {
if (dataapi.hasError) print(dataapi.error);
return dataapi.hasData
? ShowChart(data: dataapi.data)
: Center(child: CircularProgressIndicator());
},
),
),
),
);
}
}
class ShowChart extends StatelessWidget {
final List<Hakedis> data;
ShowChart({this.data});
List<charts.Series<dynamic, num>> _createSampleData(dataAPI) {
return [
new charts.Series<Hakedis, num>(
id: 'dis adet',
colorFn: (_, __) => charts.MaterialPalette.blue.shadeDefault,
areaColorFn: (_, __) =>
charts.MaterialPalette.blue.shadeDefault.lighter,
//x-axis
domainFn: (Hakedis hakedis, int number) {
return number;
},
//y-axis
measureFn: (Hakedis hakedis, _) =>
double.tryParse(hakedis.disadet).round(),
data: dataAPI,
)
];
}
#override
Widget build(BuildContext context) {
return Container(
child: charts.LineChart(
_createSampleData(data),
defaultRenderer:
new charts.LineRendererConfig(includeArea: true, stacked: true),
animate: true,
domainAxis: charts.NumericAxisSpec(
tickProviderSpec:
charts.BasicNumericTickProviderSpec(zeroBound: false),
),
),
);
}
}
String jsonString = '''[
{
"santiye1":"TSK_Ankara",
"tarih":"August",
"disadet":"1252"
},
{
"santiye1":"TSK_Ankara",
"tarih":"September",
"disadet":"6528"
},
{
"santiye1":"KMO_Istanbul",
"tarih":"August",
"disadet":"4382"
},
{
"santiye1":"KMO_Istanbul",
"tarih":"September",
"disadet":"3317"
},
{
"santiye1":"izmit",
"tarih":"January",
"disadet":"400"
},
{
"santiye1":"izmit",
"tarih":"February",
"disadet":"7883"
},
{
"santiye1":"izmit",
"tarih":"March",
"disadet":"9601"
},
{
"santiye1":"izmit",
"tarih":"April",
"disadet":"25692"
},
{
"santiye1":"izmit",
"tarih":"May",
"disadet":"15714"
},
{
"santiye1":"izmit",
"tarih":"June",
"disadet":"28024"
},
{
"santiye1":"izmit",
"tarih":"July",
"disadet":"18179"
},
{
"santiye1":"izmit",
"tarih":"December",
"disadet":"3612"
},
{
"santiye1":"Akkuyu1",
"tarih":"April",
"disadet":"10981"
},
{
"santiye1":"Akkuyu1",
"tarih":"May",
"disadet":"4384"
},
{
"santiye1":"Akkuyu1",
"tarih":"June",
"disadet":"8330"
},
{
"santiye1":"Akkuyu1",
"tarih":"July",
"disadet":"5037"
},
{
"santiye1":"Akkuyu1",
"tarih":"August",
"disadet":"6730"
},
{
"santiye1":"Akkuyu1",
"tarih":"September",
"disadet":"3523"
}
]''';
Model for the api :
// final data = dataFromJson(jsonString);
import 'dart:convert';
List<Hakedis> dataFromJson(String str) =>
List<Hakedis>.from(json.decode(str).map((x) => Hakedis.fromJson(x)));
String dataToJson(List<Hakedis> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class Hakedis {
String santiye1;
String tarih;
String disadet;
Hakedis({this.santiye1, this.tarih, this.disadet});
Hakedis.fromJson(Map<String, dynamic> json) {
santiye1 = json['santiye1'];
tarih = json['tarih'];
disadet = json['disadet'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['santiye1'] = this.santiye1;
data['tarih'] = this.tarih;
data['disadet'] = this.disadet;
return data;
}
}
Check the example and let me know if it works
I have a Complex map on Dart with the following structure
{
"India":["Mumbai","Delhi"],
"Australia":["Sydney","Perth" ,"Queensland" ],
"USA":["LA","New York"]
}
I am implementing a search using search delegate in flutter. But not able to query the data using Edit Text.
I am trying to search via City in-country in the above example. how can I do this?
For Example if user type "M" then city with M letter should be shown with country name
Thank you so much.
You just need to iterate over Map, then the value of List like this :
Map<String, List<String>> dataMap = {}; // your data map above
String query; // your search query
List<String> list = []; // list to store the results
if (query.isNotEmpty) {
dataMap.forEach((country, cities) {
cities.forEach((city) {
if (city.toLowerCase().startsWith(query.toLowerCase())) {
list.add('$city, $country');
}
});
});
}
Here the working example :
import 'package:flutter/material.dart';
final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyWidget(),
),
),
);
}
}
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return OutlinedButton.icon(
icon: Icon(Icons.search),
label: Text('Search'),
onPressed: () async {
final result = await showSearch(
context: context,
delegate: CustomSearchDelegate(),
);
print(result);
},
);
}
}
class CustomSearchDelegate<String> extends SearchDelegate<String> {
final dataMap = {
"India": [
"Mumbai",
"Delhi",
],
"Australia": [
"Sydney",
"Perth",
"Queensland",
],
"USA": [
"LA",
"New York",
]
};
#override
List<Widget> buildActions(BuildContext context) {
return [
if (query.isNotEmpty)
IconButton(
icon: Icon(Icons.clear),
onPressed: () {
query = '';
},
),
];
}
#override
Widget buildLeading(BuildContext context) {
return BackButton(
onPressed: () {
close(context, null);
},
);
}
#override
Widget buildResults(BuildContext context) {
return buildSuggestions(context);
}
#override
Widget buildSuggestions(BuildContext context) {
List<String> list = [];
if (query.isNotEmpty) {
dataMap.forEach((country, cities) {
cities.forEach((city) {
if (city.toLowerCase().startsWith(query.toLowerCase())) {
list.add('$city, $country');
}
});
});
}
return ListView(
children: ListTile.divideTiles(
context: context,
tiles: list.map((data) {
return ListTile(
title: Text(data),
onTap: () {
close(context, data);
},
);
}),
).toList(),
);
}
}
I have a registration form in my application and I want to check if the DropDown value is empty or not. So I will give a warning to the screen. But I couldn't use DropDown value on checkFieldStatus function. How can I get this?
These are my codes that i used for my app:
class Register extends StatefulWidget {
#override
_RegisterState createState() => _RegisterState();
}
class _RegisterState extends State<Register> {
List listGender = ["Erkek", "Kız"];
List listTeacher = ["Oğulcan Baybars", "Kübra Yeşilkazak"];
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
String genderHolder;
String teacherHolder;
var _imageFile = null;
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Form(
key: _formKey,
child: Column(
children: [
CustomDropDownField(
list: listGender,
hintText: "Cinsiyet",
value: genderHolder,
),
CustomDropDownField(
list: listTeacher,
hintText: "Öğretmeniniz",
value: teacherHolder,
),
ElevatedButton(
onPressed: () {
checkFieldStatus();
},
child: Text("Kayıt Ol")),
],
),
),
);
}
Future<void> checkFieldStatus() async {
if (_imageFile != null) {
showDialog(
context: context,
builder: (context) {
return ErrorAlertDialog(
message: "Resim yüklendi",
);
});
} else {
**Where I want to do the checks**
? registerUser()
: displayDialog("Lütfen formdaki bütün alanları doldurun.";
}
}
}
My CustomDropDownField like this:
import 'package:flutter/material.dart';
class CustomDropDownField extends StatefulWidget {
final List list;
final String hintText;
String value;
CustomDropDownField({
Key key,
this.list,
this.hintText,
this.value,
}) : super(key: key);
#override
_CustomDropDownFieldState createState() => _CustomDropDownFieldState();
}
class _CustomDropDownFieldState extends State<CustomDropDownField> {
#override
Widget build(BuildContext context) {
return Container(
child: DropdownButton(
isExpanded: true,
hint: Text(widget.hintText),
items: widget.list.map((valueItem) {
return DropdownMenuItem(value: valueItem, child: Text(valueItem));
}).toList(),
value: widget.value,
onChanged: (newValue) {
setState(() {
widget.value = newValue;
});}),);}
CustomDropDownField only changes the String value in its own state it does not reflect to the _RegisterState screen you can do a few different things:
Pass a callback function that updates the value in the _RegisterState screen
or even better
Use a state management like Provider or Bloc to update the value.
My small app, is getting list of users from JSON link then store it in the List, I wanna this list into usersCollection collection ref of firestore
my code
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'dart:async';
import 'package:http/http.dart' as http;
import 'package:yat_flutter_app/main.dart';
import 'usersList.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
CollectionReference usersCollection =
FirebaseFirestore.instance.collection('users');
Future<List<User>> getUsers() async {
var data = await http
.get("https://www.json-generator.com/api/json/get/bYKKPeXRcO?indent=2");
var jasonData = json.decode(data.body);
List<User> users = [];
for (var i in jasonData) {
User user = User(i["index"], i["about"], i["name"], i["picture"],
i["company"], i["email"]);
users.add(user);
}
return users;
}
#override
Widget build(BuildContext context) {
List<User> usersList = getUsers() as List<User>;
return Container(
child: Column(
children: [
FutureBuilder(
future: getUsers(),
builder: (BuildContext context, AsyncSnapshot asyncSnapshop) {
if (asyncSnapshop.hasData) {
return Expanded(
child: ListView.builder(
shrinkWrap: true,
itemCount: asyncSnapshop.data.length,
itemBuilder: (BuildContext context, int index) {
return Card(
elevation: 5,
color: Colors.cyan[50],
child: ListTile(
trailing: Icon(Icons.share),
title: Text(asyncSnapshop.data[index].name, style: TextStyle(fontFamily: 'Tahoma',fontSize: 20,fontWeight: FontWeight.bold),),
leading: CircleAvatar(
backgroundImage: NetworkImage(
asyncSnapshop.data[index].picture +
asyncSnapshop.data[index].index.toString() +
".jpg"),
),
subtitle: Text(asyncSnapshop.data[index].email,style: TextStyle(fontFamily: 'Tahmoma',fontSize: 18),),
onTap: (){
Navigator.push(context, new MaterialPageRoute(builder: (context)=>
detailsPage(asyncSnapshop.data[index])
));
},
onLongPress: ()=>
Fluttertoast.showToast(
msg: asyncSnapshop.data[index].name,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor: Colors.green[900],
textColor: Colors.white,
fontSize: 16.0
),
),
);
}),
);
} else {
return Text("Loading, please wait...");
}
},
),
ElevatedButton(
child: Text('Save data'),
onPressed: () => {
usersCollection.add(getUsers()); // here's I am trying to add the result of getUsers into usersCollection
}),
],
),
);
}
}
To push an object to Firestore you need to convert your object to map.
You can just add this function to your class:
Map<String, dynamic> toMap() {
return {
'field1': value1,
'field2': value1,
};
}
To push a List , you need to convert all objects to map, you can do it with following method:
static List<Map> ConvertToMap({List myList }) {
List<Map> steps = [];
myList.forEach((var value) {
Map step = value.toMap();
steps.add(step);
});
return steps;
}
Or simply , see how to convert List to Map
I hope it will be useful
To push this list to Firestore you need to fromJson and toJson methods in your model class
factory User.fromJson(Map<String, dynamic> data){
return User(
index: data['index'] as int,
about: data['about'] as String,
name: data['name'] as String,
picture: data['picture'] as String,
company: data['company'] as String,
email: data['email'] as String );
}
Map<String, dynamic> toJson(){
return {
"index": index,
"about" : about,
"name" : name,
"picture" : picture,
"company" : company,
"email" : email,
};
}
instead that I would like to suggest using json_serializable library
then you need to do some changes in your future method like this
getUsers().then((users) {
// add users to map
});
and then you can use fromJson method to push it to firestore database
Firebase realtime database and firestore are no SQL databases where data will be stored in Parent child relation or Tree structure.
For you to store list of data you can convert your list into Map
Map can be initialised as follows
Map<String, String> toMap() {
return {
'Fruit': "Mango",
'Flower': "Lotus",
'Vegetable': "Potato",
};
}
After you have Map you can set value to the firestore. You can use the below code to set value
Map<String, Object> city = new Map<>();
//Loop through your list and load Map (City) values
db.collection("cities").document("LA").set(city)
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Log.d(TAG, "DocumentSnapshot successfully written!");
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.w(TAG, "Error writing document", e);
}
});
You can convert List of items to map using this
Java: How to convert List to Map
so i'm working on a Map that has this structure :
Map<String, List<Video>> mapName;
Where Video is just an object that has 3 attributes : String title,String videoURL, bool isDone.
I'm planing on creating a listView that will display all Video titles so i'm just trying to figure out how to get the length of the list that exists into the Map.
I tryed some test and it displayed this :
print(videoList.values.map((list) => list.length));
I/flutter (23887): (9)
Now its true that i have 9 videos in the list, but I cannot use this in my listview itemcount because it requires an int type data.
If your Map have more than one list of videos by the key String of the Map, you can get all lengths using this code:
Map<String, List<Video>> mapName = {
'video1': [Video(),Video()],
'video2': [Video()],
'video3': [Video(),Video(),Video()],
}; //Init
int total = 0;
mapName.keys.forEach((key){
List<Video> video = mapName[key];
int length = video.length;
print('$key: $length');
total += length;
});
print('total: $total');
Flutter Example:
import 'package:flutter/material.dart';
final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class Video {
final String name;
final String url;
final bool isDone;
Video(this.name, this.url, this.isDone);
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
Map<String, List<Video>> mapName = {
'video1': [
Video('Bunny', 'http://????', false),
Video('Bunny10', 'http://????', true),
],
'video2': [
Video('Bunny2', 'http://????', false),
],
'video3': [
Video('BunnyX', 'http://????', false),
Video('Bunny12', 'http://????', true),
Video('BunnyZZ', 'http://????', false),
],
}; //Init
List<Video> mVideos = [];
mapName.values.forEach((videos) {
videos.forEach((video) {
mVideos.add(video);
});
});
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: ListView.builder(
itemCount: mVideos.length,
itemBuilder: (context, index) {
Video video = mVideos[index];
String name = video.name;
String url = video.url;
bool isDone = video.isDone;
return ListTile(
tileColor: isDone ? Colors.green : null,
title: Text(name),
subtitle: Text(url),
);
},
),
),
);
}
}
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Text('Hello, World!', style: Theme.of(context).textTheme.headline4);
}
}