Home > Net >  show filtered record while typing in textfield with StreamBuilder in flutter
show filtered record while typing in textfield with StreamBuilder in flutter

Time:11-13

I have created a simple demo page for learning firebase,

here I have a textfield, searchbutton and StreamBuilder for showing all records

I have placed a condition for showing all records when textfield is empty...

here I have used a button which just rebuild...just used setState inside it onpressed

everything working well, but I just want to improve that record should be filter while typing on textfield so that no need of button there.

how to call StreamBuilder's stream in textfield change.... and in addition, I have created customTextField,,so how to pass function as onChange requires a value...

here is my coding

Column(
          children: [
            SizedBox(
              height: 40,
            ),
            CustomTextField(
                hint: 'Search Email', controller: txtsearchcontroller),
            SizedBox(
              height: 20,
            ),
            CupertinoButton(
                child: Text('Search'),
                onPressed: () {
                  setState(() {});
                }),
            SizedBox(
              height: 30,
            ),
            StreamBuilder(
                stream: txtsearchcontroller.text == ''
                    ? FirebaseFirestore.instance
                        .collection('chatusers')
                        .snapshots()
                    : FirebaseFirestore.instance
                        .collection('chatusers')
                        .where(
                          "email",
                          isEqualTo: txtsearchcontroller.text,
                          isNotEqualTo: widget.usermodel.email,
                        )
                        .snapshots(),
                builder: (context, snapshot) {
                  if (snapshot.connectionState == ConnectionState.active) {
                    if (snapshot.hasData) {
                      QuerySnapshot querysnapshot =
                          snapshot.data as QuerySnapshot;
                      if (querysnapshot.docs.length > 0) {
                        //and suggest me if any better way instead of this following
                        List<Map<String, dynamic>> maplist = [];
                        for (int x = 0; x < querysnapshot.docs.length; x  ) {
                          Map<String, dynamic> usermap = querysnapshot.docs[x]
                              .data() as Map<String, dynamic>;
                          maplist.add(usermap);
                        }

                        return Expanded(
                          child: CustomListView(maplist:maplist),
                        );
                      } else {
                        return Text('Has Data but No user Found');
                      }
                    } else {
                      if (snapshot.hasError) {
                        return Text('error found');
                      } else {
                        return Text('empty..');
                      }
                    }
                  } else {
                    return CircularProgressIndicator();
                  }
                }),

here is my CustomTextField

class CustomTextField extends StatelessWidget {

  final String hint;
  final bool isitpassword;
  final TextEditingController controller;
  const CustomTextField({Key? key,required this.hint,this.isitpassword=false,required this.controller}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 10.0),
      child: Container(
          padding: EdgeInsets.symmetric(horizontal: 20),
          decoration: BoxDecoration(
            color: Colors.grey,
            borderRadius: BorderRadius.circular(20),
          ),

          child: TextField(
            style: TextStyle(
              fontSize: 20,color: Colors.white,),

            controller: controller,
            obscureText: isitpassword,
            decoration: InputDecoration(

              border: InputBorder.none,
              hintText: hint,
              suffixIcon: IconButton(icon: Icon(Icons.close,color: Colors.white,),onPressed: (){
                controller.text='';
              },),

            ),
          )),
    );
  }
}

CodePudding user response:

TextField widget has an onChanged property, which will execute every time the input is changed.

in the CustomTextField, add the onChanged property :

 TextField(
        onChanged: (value) { SetState(() {})},
        
        /* your other properties ...*/
        ),

this will give you what you need, but since you're calling CustomTextField which contains that TextField, pass the onChanged method from the constructor so you can use it like this:

 CustomTextField(
        onChanged: () { SetState(() {})},
        hint: 'Search Email', controller: txtsearchcontroller),
        SizedBox(
          height: 20,
        ),

now every time the input changes, a SetState(() {}) will be executed causing rebuild.

CodePudding user response:

You can use StreamController for this purpose. For example,

enum SearchState {
  INITIAL,
  LOADING,
  LOADED,
}

StreamController<SearchState> searchController = StreamController.broadcast()..add(SearchState.INITIAL);

List<ChatUser?> searchResult = []; // your filtered results
 List<ChatUser?> users = []; // all users

void searchOperation({required String searchText}) { 
    searchController.add(SearchState.LOADING); // User is typing

    searchResult.clear();
    for (var element in users) {
      final word = element?.username?.trim();
      if (word?.toLowerCase().contains(searchText.toLowerCase()) == true) { // your equality logic here
        searchResult.add(element);
      }
    }

    searchController.add(SearchState.LOADED);
  }

Then you should give a searchController to StreamBuilder ,

StreamBuilder<SearchState>(
      stream: searchController.stream,
      builder: (context, snapshot) {
        if (snapshot.data == SearchState.LOADING) { // draw your ui ..
          return const Center(
            child: CircularProgressIndicator(),
          );
        }...

Maybe you may want to check full example on my repository here , https://github.com/SamedHrmn/flutter-playgrounds/tree/master/textfield_searching

  • Related