How to make a Textfield search in Listview.builder update with setState() inside a Dialog using statefulBuilder

Viewed 170

I'm very new to flutter and I have found several videos and posts about AlertDialog and StatefulBuilder, however I do not understand how it works enough to apply it to my own scenario.

Essentially I have a class that stores a book name and book cover photo, and I have a custom search widget that builds a text field and filters through a List view of all the books. I've tested the functionality of the code and it works as intended outside of the Dialog(), however, the when inside the Dialog() the state does not get updated and the search function does not work.

Here is the script that I am trying to fix. I do import the search widget and the book list from other files. Supposedly it's an easy fix with a StatefulBuilder, but I really can't seem to get a grasp on it. Any help with specific examples and explanations with respect to my code would be really appreciated.

import 'package:flutter/material.dart';
import 'Universal Classes and Vars/List.dart';
import 'Widgets/searchWidget.dart';

class BuildTemplate extends StatefulWidget {
  @override
  _BuildTemplateState createState() => _BuildTemplateState();
}

class _BuildTemplateState extends State<BuildTemplate> {
  List<Book> currentTemplate = [];
  late List<Book> books;
  String searchText = '';

  void initState() {
    super.initState();

    books = bookList;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.grey[100],
      appBar: AppBar(title: Text("New Page")),
      body: Stack(children: [
        Column(children: [
          Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
            Text("Custom Template"),
            IconButton(onPressed: () {}, icon: Icon(Icons.add))
          ]),
          Expanded(
            child: SizedBox(
                width: 500,
                child: ListView.builder(
                    itemCount: currentTemplate.length + 1,
                    itemBuilder: (context, index) =>
                        index < currentTemplate.length
                            ? Card(
                                child: ListTile(
                                onTap: () {},
                                title: Text(currentTemplate[index].name),
                                leading: CircleAvatar(
                                  backgroundImage:
                                      AssetImage(currentTemplate[index].image),
                                ),
                              ))
                            : ElevatedButton(
                                child: Text("Add Element"),
                                style: ButtonStyle(),
                                onPressed: () {
                                  openDialog();
                                },
                              ))),
          ),
        ]),
      ]),
    );
  }

  Widget buildSearch() => SearchWidget(
        text: searchText,
        hintText: 'Search',
        onChanged: searchBook,
      );

  Widget buildBook(Book book) => Card(
          child: ListTile(
        onTap: () {},
        title: Text(book.name),
        leading: CircleAvatar(
          backgroundImage: AssetImage(book.image),
        ),
      ));

  void searchBook(String searchText) {
    final books = bookList.where((element) {
      final nameLower = element.name.toLowerCase();
      final searchLower = searchText.toLowerCase();
      return nameLower.contains(searchLower);
    }).toList();

    setState(() {
      this.searchText = searchText;
      this.books = books;
    });
  }

  openDialog() => showDialog(
      context: context,
      builder: (context) => StatefulBuilder(
            builder: (context, setState) => Dialog(
              child: Center(
                child: Container(
                    color: Colors.grey,
                    margin: EdgeInsets.symmetric(horizontal: 20, vertical: 30),
                    padding: EdgeInsets.all(15),
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        buildSearch(),
                        SizedBox(
                          height: 10,
                        ),
                        Expanded(
                          child: ListView.builder(
                            itemCount: books.length,
                            itemBuilder: (context, index) {
                              final book = books[index];

                              return buildBook(book);
                            },
                          ),
                        ),
                      ],
                    )),
              ),
            ),
          ));
}
1 Answers

Based on the documentation Dialog has no implementation of the Materialapp. Maybe you could change to AlertDialog or SimpleDialog. Because of the use of Scaffold.

Related