1

I'm trying to figure out how to render a list from a specific collection in firebase and to change that list when selecting options from dropdown menu. I could get the list rendered on 1 collection, but when I add my dropdown menu, with the default value being 'lost', nothing is displayed. Here's what I have so far that works, but not entirely what I want.

class _ListPageState extends State<ListPage>{
  List<String> _type = ['lost', 'found'];
  String _selectedView = 'lost';

//this getData pulls from 'lost' collection, since I set _selectedView to lost by default
  Future getData() async{
    var firestore = Firestore.instance;
    QuerySnapshot qn = await firestore.collection(_selectedView).getDocuments();
    return qn.documents;
  }

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

    return new DropdownButtonFormField(
      value: _selectedView,
      onChanged: (newValue) {
        setState(() {
          _selectedView = newValue;
        });
      },
      items: _type.map((view) {
        return new DropdownMenuItem(
          child: new Text(view),
          value: view,
        );
      }).toList(),
    );
  }
  @override
  Widget build(BuildContext context){
    return ListView(
      children: <Widget>[
        _viewType(),
        FutureBuilder(//it's not rendering any of this when adding the dropdown above it
          future: getData(),
          builder: (_, snapshot){
        if(snapshot.connectionState == ConnectionState.waiting){
          return Center(
            child: Text("Loading"),
          );
        }
        else{
          return ListView.builder(
              itemCount: snapshot.data.length,
              itemBuilder: (_, index){
              return ListTile(
                title: Text(snapshot.data[index].data["Title"]),
                onTap: () => navigateToDetail(snapshot.data[index]),
              );
          });

        }
      }),]
    );
  }
}

Thanks in advance for any help. Please let me know if there's any more code you'd like to see. I this I have to wrap part of it with setState(), but I'm not quite sure where.

3
  • Can you provide the code that was "making the error" so we can see your problem? Maybe we can highlight on your possible mistake so you and others can benefit. It would be appreciated :) Commented Nov 6, 2019 at 1:28
  • 1
    Thank you. I modified the code to my attempt at getting both the dropdown and the collection from firebase to render. When I do it this way, I get my drop down, but my list doesn't populate. This way isn't meant to determine value set in dropdown (yet). Just trying to get them to display, but my ultimate goal must be to setState somewhere to re-render the build widget with a new collection listed. Commented Nov 6, 2019 at 1:38
  • 1
    The error message for this attempt is: RenderBox was not laid out: RenderRepaintBoundary#a8c0a relayoutBoundary=up5 NEEDS-PAINT 'package:flutter/src/rendering/box.dart': Failed assertion: line 1681 pos 12: 'hasSize' Commented Nov 6, 2019 at 1:39

1 Answer 1

2

Thanks for the fast clarification.

What is happening here is that you have put a ListView inside a ListView. You should use a Column.

By default (as mentioned in the documentation):

The Column widget does not scroll (and in general it is considered an error to have more children in a Column than will fit in the available room). If you have a line of widgets and want them to be able to scroll if there is insufficient room, consider using a ListView.

In your case, you want to place a ListView that will overflow the Column that can't scroll. To avoid that, consider using an Expanded to take the remaining space so that the height is somehow constrained and the ListView knows its limits and work properly.

class _ListPageState extends State<ListPage> {
  List<String> _type = ['lost', 'found'];
  String _selectedView = 'lost';

//this getData pulls from 'lost' collection, since I set _selectedView to lost by default
  Future getData() async {
    var firestore = Firestore.instance;
    QuerySnapshot qn = await firestore.collection(_selectedView).getDocuments();
    return qn.documents;
  }

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

  Widget _viewType() {
    return new DropdownButtonFormField(
      value: _selectedView,
      onChanged: (newValue) {
        setState(() {
          _selectedView = newValue;
        });
      },
      items: _type.map((view) {
        return new DropdownMenuItem(
          child: new Text(view),
          value: view,
        );
      }).toList(),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        _viewType(),
        Expanded(
          child: FutureBuilder(
            //it's not rendering any of this when adding the dropdown above it
            future: getData(),
            builder: (_, snapshot) {
              if (snapshot.connectionState == ConnectionState.waiting) {
                return Center(
                  child: Text("Loading"),
                );
              } else {
                return ListView.builder(
                  itemCount: snapshot.data.length,
                  itemBuilder: (_, index) {
                    return ListTile(
                      title: Text(snapshot.data[index].data["Title"]),
                      onTap: () => navigateToDetail(snapshot.data[index]),
                    );
                  },
                );
              }
            },
          ),
        ),
      ],
    );
  }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Woo hoo! Thank you very much. After that rendered properly, it also fixed the conditional state based on drop down menu choice.
I couldn't figure out what type of container I needed to put that in as well. Thank you for the detailed explanation for other container choices.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.