Home > OS >  Flutter - Filtering a DropDown button
Flutter - Filtering a DropDown button

Time:04-28

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

  • Related