I've got a class function that returns a ListTile of a Map, and I'm trying to filter that ListTile through a user-selected DropDown button. It compiles and works until I click one of the drop down selections and returns this:
Error: Expected a value of type 'List<dynamic>', but got one of type 'ItemInformation'
at Object.throw_ [as throw] (http://localhost:59875/dart_sdk.js:5069:11)
at Object.castError (http://localhost:59875/dart_sdk.js:5028:15)
at Object.cast [as as] (http://localhost:59875/dart_sdk.js:5353:17)
at Function.as_C [as as] (http://localhost:59875/dart_sdk.js:4974:19)
at http://localhost:59875/packages/foundit/screens/search.dart.lib.js:528:50
at search._SearchPage.new.setState (http://localhost:59875/packages/flutter/src/widgets/widget_inspector.dart.lib.js:13365:22)
at http://localhost:59875/packages/foundit/screens/search.dart.lib.js:525:30
at http://localhost:59875/packages/flutter/src/material/dropdown.dart.lib.js:2728:31
at _RootZone.runUnary (http://localhost:59875/dart_sdk.js:40497:59)
at _FutureListener.then.handleValue (http://localhost:59875/dart_sdk.js:35424:29)
at handleValueCallback (http://localhost:59875/dart_sdk.js:35985:49)
at Function._propagateToListeners (http://localhost:59875/dart_sdk.js:36023:17)
at _Future.new.[_completeWithValue] (http://localhost:59875/dart_sdk.js:35858:23)
at async._AsyncCallbackEntry.new.callback (http://localhost:59875/dart_sdk.js:35892:35)
at Object._microtaskLoop (http://localhost:59875/dart_sdk.js:40764:13)
at _startMicrotaskLoop (http://localhost:59875/dart_sdk.js:40770:13)
at http://localhost:59875/dart_sdk.js:36247:9
What am I doing wrong? Here's my code for ItemInformation:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class ItemInformation extends StatefulWidget {
@override
_ItemInformationState createState() => _ItemInformationState();
}
class _ItemInformationState extends State<ItemInformation> {
final Stream<QuerySnapshot> _itemsStream = FirebaseFirestore.instance.collection('items').snapshots();
@override
Widget build(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: _itemsStream,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Text("Loading");
}
var list = snapshot.data!.docs.map((DocumentSnapshot document) {
Map<String, dynamic> data = document.data()! as Map<String, dynamic>;
return data;
}
);
return Text('error');
},
);
}
}
Here's my code for home screen.dart (where the table takes place):
import 'dart:async';
import 'package:flutter/widgets.dart';
import 'package:foundit/widgets/items.dart';
import 'package:foundit/widgets/mainmenu.dart';
import 'package:flutter/material.dart';
import 'package:foundit/widgets/itemstable.dart';
class FoundItHomePage extends StatefulWidget {
const FoundItHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<FoundItHomePage> createState() => _FoundItHomePageState();
}
class _FoundItHomePageState extends State<FoundItHomePage> {
String? _chosenLocation;
String? _chosenType;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text('Found It!'),
leadingWidth:100,
actions: <Widget>[
IconButton(
icon: const Icon(Icons.login),
tooltip: 'Log in to add new items and see existing items',
onPressed: () {
Navigator.pop(context);
Navigator.pushNamed(context, '/admin');
},
),
],
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
DropdownButton<String>(
value: _chosenType,
//elevation: 5,
style: TextStyle(color: Colors.black),
items: <String>['Item Type','shirt','shorts','pants', 'skirt', 'outer wear', 'water bottle', 'keys', 'wallet', 'device', 'book/binder', 'miscellaneous'].map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value,
style: const TextStyle(
color: Colors.black,
fontSize: 16,
fontWeight: FontWeight.w600),
),
);
}).toList(),
hint: const Text(
"Item Type",
style: TextStyle(
color: Colors.black,
fontSize: 16,
fontWeight: FontWeight.w600),
),
onChanged: (String? value) {
setState(() {
_chosenType = value;
if(_chosenType != 'Item Type'){
List data = ItemInformation() as List;
data.where((element) => element.type.contains(_chosenType)).toList();
};
},
);
},
),
const SizedBox(
width: 20,
),
DropdownButton<String>(
value: _chosenLocation,
//elevation: 5,
style: TextStyle(color: Colors.black),
items: <String>['Location','Lower School Office', 'Middle School Office', 'Upper School Office', 'Lower School Library','Middle School Library','Upper School Library' ,'Lunch Room', 'Athletic Office'].map<DropdownMenuItem<String>>((String value){
return DropdownMenuItem<String>(
value: value,
child: Text(value,
style: const TextStyle(
color: Colors.black,
fontSize: 16,
fontWeight: FontWeight.w600),
),
);
}).toList(),
hint: const Text(
"Location",
style: TextStyle(
color: Colors.black,
fontSize: 16,
fontWeight: FontWeight.w600),
),
onChanged: (String? value) {
setState(() {
_chosenLocation = value;
if(_chosenLocation != 'Location'){
List data = ItemInformation() as List;
data.where((element) => element.title.contains(_chosenLocation)).toList();
};
},
);
},
),
const SizedBox(
width: 20,
),
],
),
),
Expanded(
child: ItemTable(),
),
],
),
),
);
}
}
Here's the code for the itemtable:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class ItemTable extends StatefulWidget {
@override
_ItemTableState createState() => _ItemTableState();
}
class _ItemTableState extends State<ItemTable> {
final Stream<QuerySnapshot> _itemsStream = FirebaseFirestore.instance.collection('items').snapshots();
@override
Widget build(BuildContext context, ) {
return StreamBuilder<QuerySnapshot>(
stream: _itemsStream,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Text("Loading");
}
List<DataRow> lostitems = snapshot.data!.docs.map((DocumentSnapshot document) {
Map<String, dynamic> data = document.data()! as Map<String, dynamic>;
return (
DataRow(
cells:
[
DataCell(Text(data['name'])),
DataCell(Text(data['type'])),
DataCell(Text(data['location'])),
]
)
);
}).toList();
return DataTable(
rows: lostitems,
columns: [
DataColumn(label: Text("Name")),
DataColumn(label: Text("Type")),
DataColumn(label: Text("Location")),
],
);
},
);
}
}
CodePudding user response:
Your ItemInformation class doesn't need to be a a flutter widget. You can make this into a dart data class. As it stands, when you are calling ItemInformation() you don't return a List. You return a Text() or a Map<String, dynamic>.
I recommend changing your ItemInformation class into a Dart class that has a method which retrieves the data and converts it into a list. Then you can call that method in one of the flutter widgets and run your loading checks there.
class ItemInformation {
List retrieveInfo() {
// Get your data from firestore
// return data
}
}
CodePudding user response:
your variabel data is List<dynamic> because you use List data = ItemInformation() as List;
try replace it List<ItemInformation> data