Search code examples
flutterlistviewgoogle-cloud-firestoredropdown

Flutter Firebase listview with filters


I have created a listview in flutter which is pulling the data from firestore. Till here it works fine, but now I want to add some filters using dropdown which will filter the listview based on dropdown values selected by the user. So right now when app loads for the first time the listview comes properly, but when I change the values in dropdown the list doesn't change. I want to update the listview when user selects the dropdown value.

enter image description here

This is the appbar where I have two filters(dropdown values). And as and when user wants to change the filter values(from the dropdown) the list should be updated.

import 'package:cloud_firestore/cloud_firestore.dart';

class LandingPage extends StatefulWidget {
  @override
  _LandingPageState createState() => _LandingPageState();
}
 String _currentlySelectedage = "2"; 
 String _currentlySelectedlanguage = "english";

  class _LandingPageState extends State<LandingPage> {
  final List<String> _dropdownValuesage = ["1","2","3"]; 
  final List<String> _dropdownValueslanguage = ["silent", "english","hindi"];
 

  Widget dropdownWidgetage() {
    return DropdownButton(
      isExpanded: false,
      value:_currentlySelectedage,
      onChanged: (String newvalue) {
        setState(() {
          _currentlySelectedage = newvalue;
          print(_currentlySelectedage);
        });
      },
      items: _dropdownValuesage
          .map((value) => DropdownMenuItem(
                child: Text(value),
                value: value,
              ))
          .toList(),
    );
  }

  Widget dropdownWidgetlanguage() {
    return DropdownButton(
      isExpanded: false,
      value:_currentlySelectedlanguage,
      onChanged: (String newvalue) {
        setState(() {
          _currentlySelectedlanguage = newvalue;
          print(_currentlySelectedlanguage);
        });
      },
      items: _dropdownValueslanguage
          .map((value) => DropdownMenuItem(
                child: Text(value),
                value: value,
              ))
          .toList(),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: new AppBar(
        centerTitle: false,
        title: Text('',style: TextStyle(fontFamily: 'Raleway'),),
        backgroundColor: Colors.teal,
        actions: <Widget>[
          dropdownWidgetage(),
          SizedBox(width:4),
          dropdownWidgetlanguage()
        ],
      ),
      body: ListPage(),
    );
  }
}

class ListPage extends StatefulWidget {
  @override
  _ListPageState createState() => _ListPageState();
}

class _ListPageState extends State<ListPage> {
  Future _data;

  Future getPosts() async {
    var firestore = Firestore.instance;
    QuerySnapshot qn = await firestore
        .collection("movies")
        .where("age", arrayContains: _currentlySelectedage)
        .where("language", isEqualTo: _currentlySelectedlanguage)
        .orderBy('rank', descending: true)
        .getDocuments();
    return qn.documents;
  }

  navigateToDetail(DocumentSnapshot post) {
    Navigator.push(
        context,
        MaterialPageRoute(
            builder: (context) => DetailPage(
                  post: post,
                )));
  }

  @override
  void initState() {
    super.initState();
    _data = getPosts();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      child: FutureBuilder(
          future: _data,
          builder: (_, snapshot) {
            if (snapshot.connectionState == ConnectionState.waiting) {
              return Center(
                child: Text("Loading...."),
              );
            } else {
              return ListView.builder(
                  itemCount: snapshot.data.length,
                  itemBuilder: (_, index) {
                    return Card(
                        child: Column(
                            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                            children: [
                          InkWell(
                            onTap: () => navigateToDetail(snapshot.data[index]),
                            child: Image.network(
                                snapshot.data[index].data['gff']),
                          ),
                          Text(
                            snapshot.data[index].data['gfg'],
                            style: TextStyle(
                                fontWeight: FontWeight.bold, fontSize: 20),
                          ),
                        ]));
                  });
            }
          }),
    );
  }
}

Solution

  • Flutter caches widgets to avoid unnecessary rebuilds. When it goes to build ListPage() the second time it sees the parameters have not changed, because there are no parameters, and reuses the cached version from the first build. Convert the global variables into parameters and you should be fine.