skip to Main Content

I have Search Modal popup where the user can search and get results based on their search. However, since the class extends ModalRoute and not a StatefulWidget, calling setState does not re-render the build and the search results do no appear on the screen. Is there a way to update the state or re-render the screen without having to convert the class to a StatefulWidfet?

class JobSerachModal extends ModalRoute {
  List<dynamic>? searchResults;

  @override
  Duration get transitionDuration => const Duration(milliseconds: 250);

  @override
  bool get opaque => false;

  @override
  bool get barrierDismissible => false;

  @override
  Color get barrierColor => Colors.black;

  @override
  String? get barrierLabel => null;

  @override
  bool get maintainState => true;


  getSearch(String query) async {
    var result = await SearchService().getAllPaged(query: query);
    setState(() {
      searchResults = result;
    });
  }

  _onSearchChanged(String query) {
    getSearch(query);
  }

  @override
  Widget buildPage(
    BuildContext context,
    Animation<double> animation,
    Animation<double> secondaryAnimation,
  ) {
    return Scaffold(
      body: SafeArea(
        child: Padding(
          padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
          child: Column(
            mainAxisSize: MainAxisSize.min,
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  Expanded(
                    child: TextField(
                      onChanged: _onSearchChanged,
                      autofocus: true,
                    ),
                  ),
                  TextButton(
                      onPressed: () => Navigator.of(context).pop(),
                      child: const Text('Cancel'))
                ],
              ),
              const SizedBox(
                height: 20,
              ),
              ...searchResults.map(
                (search) {
                  return ListTile(
                    title: Text(search.title),
                  );
                },
              )
            ],
          ),
        ),
      ),
    );
  }
}

2

Answers


  1.  StatefulBuilder(
        builder: (BuildContext context, setState) {
          return ;
        },
      ),
    

    Use StatefulBuilder

    Example:

    await showDialog<void>(
      context: context,
      builder: (BuildContext context) {
        int? selectedRadio = 0;
        return AlertDialog(
          content: StatefulBuilder(
            builder: (BuildContext context, StateSetter setState) {
              return Column(
                mainAxisSize: MainAxisSize.min,
                children: List<Widget>.generate(4, (int index) {
                  return Radio<int>(
                    value: index,
                    groupValue: selectedRadio,
                    onChanged: (int? value) {
                      setState(() => selectedRadio = value);
                    },
                  );
                }),
              );
            },
          ),
        );
      },
    );
    
    Login or Signup to reply.
  2. Flutters setState() method is only available within a StatefulWidget to rebuild the widgets when there is a state change. You can not call setState() method from ModalRoute since it doesn’t exist there.

    You could use ValueNotifier and ValueListenableBuilder to achieve your goal.

    The Code:

    // Define a new class JobSearchModal that extends ModalRoute
    class JobSearchModal extends ModalRoute {
      // Declare a ValueNotifier which will notify all the listeners whenever there's a change in search results
      final ValueNotifier<List<dynamic>> searchResults = ValueNotifier<List<dynamic>>([]);
    
      // Set duration of transition
      @override
      Duration get transitionDuration => const Duration(milliseconds: 250);
    
      @override
      bool get opaque => false;
    
      @override
      bool get barrierDismissible => false;
    
      @override
      Color get barrierColor => Colors.black;
    
      @override
      String? get barrierLabel => null;
    
      @override
      bool get maintainState => true;
    
      // Define this asynchronous function to get search results
      getSearch(String query) async {
        var result = await SearchService().getAllPaged(query: query);
        searchResults.value = result;
      }
    
      // Define a function that gets executed when a search query changes
      _onSearchChanged(String query) {
        getSearch(query);
      }
    
      @override
      Widget buildPage(
        BuildContext context,
        Animation<double> animation,
        Animation<double> secondaryAnimation,
      ) {
        return Scaffold(
          body: SafeArea(
            child: Padding(
              padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
              child: Column(
                mainAxisSize: MainAxisSize.min,
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      Expanded(
                        child: TextField(
                          onChanged: _onSearchChanged,
                          autofocus: true,
                        ),
                      ),
                      TextButton(
                          onPressed: () => Navigator.of(context).pop(),
                          child: const Text('Cancel'))
                    ],
                  ),
                  const SizedBox(
                    height: 20,
                  ),
                  ValueListenableBuilder(
                    valueListenable: searchResults,
                    builder: (context, value, child) {
                      return Column(
                        children: value.map(
                          (search) {
                            return ListTile(
                              title: Text(search.title),
                            );
                          },
                        ).toList(),
                      );
                    },
                  )
                ],
              ),
            ),
          ),
        );
      }
    }
    
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search