Search code examples
firebaseflutterlistviewsearch

Flutter: How to search from FutureBuilder Listview


I am new to flutter and trying to finish the last remaining part of my app. I am using Firebase realtime database to store out employee data and listing it using a ListView.builder. I am able to show all the information in the list but I want to implement the search bar. I started off and have it in a controller and shows in the terminal but not sure how to implement it properly to filter the data.

I will past my full code but remove the firebase database as it is open right now for testing.

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'dart:async';
import 'directory_details_screen.dart';

class Directory extends StatefulWidget {
  // const ({Key? key}) : super(key: key);

  @override
  _DirectoryState createState() => _DirectoryState();
}

class _DirectoryState extends State<Directory> {
  TextEditingController _searchController = TextEditingController();

  Future getEmpData() async {
    var response = await http.get(Uri.parse(
        'FIREBASE REMOVED'));
    var jsonData = jsonDecode(response.body);
    List<Employee> employees = [];

    for (var e in jsonData) {
      Employee employee = Employee(
          e["displayName"],
          e["department"],
          e["jobTitle"],
          e["mobilePhone"],
          e["workEmail"],
          e["photoUrl"],
          e["workPhoneExtension"]);
      employees.add(employee);
    }
    print(employees.length);
    return employees;
  }


  @override
  void initState() {
    super.initState();
    _searchController.addListener(_onSearchChanged);
  }

  @override
  void dispose() {
    _searchController.removeListener(_onSearchChanged);
    _searchController.dispose();
    super.dispose();
  }

  _onSearchChanged() {
    print(_searchController.text);
  }

  String searchString = "";

  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        mainAxisSize: MainAxisSize.max,
        mainAxisAlignment: MainAxisAlignment.start,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          SizedBox(height: 10),
          Padding(
            padding: const EdgeInsets.symmetric(horizontal: 15.0),
            child: TextField(
              onChanged: (value) {
                setState(() {
                  searchString = value;
                });
              },
              controller: _searchController,
              decoration: InputDecoration(
                labelText: 'Search',
                suffixIcon: Icon(Icons.search),
              ),
            ),
          ),
          SizedBox(height: 10),
          Expanded(
            child: FutureBuilder(
              future: getEmpData(),
              builder: (context, AsyncSnapshot snapshot) {
                if (snapshot.data == null) {
                  return Container(
                    child: Center(
                      child: CircularProgressIndicator(),
                    ),
                  );
                } else
                  return ListView.builder(
                      itemCount: snapshot.data!.length,
                      itemBuilder: (context, i) {
                        return Card(
                          child: ListTile(
                            leading: CircleAvatar(
                              backgroundImage: NetworkImage(
                                snapshot.data[i].photoUrl
                              ),
                            ),
                            //leading: Icon(Icons.account_circle),
                            isThreeLine: true,
                            title: Text(snapshot.data[i].displayName,
                                style: TextStyle(fontWeight: FontWeight.bold)),
                            subtitle: Text("Department: " +
                                snapshot.data[i].department +
                                "\n" +
                                "Title: " +
                                snapshot.data[i].jobTitle),
                            onTap: () {
                              Navigator.of(context).push(MaterialPageRoute(
                                  builder: (context) => EmployeeDetails(
                                      employee: snapshot.data[i])));
                            },
                          ),
                        );
                      });
              },
            ),
          ),
        ],
      ),
    );
  }
}

class Employee {
  final String displayName,
      department,
      jobTitle,
      mobilePhone,
      workEmail,
      photoUrl,
      workPhoneExtension;
  Employee(this.displayName, this.department, this.jobTitle, this.mobilePhone,
      this.workEmail, this.photoUrl, this.workPhoneExtension);
}


Solution

  • You can try something like this:

    ...
    } else {
    final result = _search(snapshot.data);
    
      return ListView.builder(
          itemCount: result.length,
          itemBuilder: (context, i) {
            return Card(
              child: ListTile(
                leading: CircleAvatar(
                  backgroundImage: NetworkImage(
                      result[i].photoUrl
                  ),
                ),
                //leading: Icon(Icons.account_circle),
                isThreeLine: true,
                title: Text(result[i].displayName,
                    style: TextStyle(fontWeight: FontWeight.bold)),
                subtitle: Text("Department: " +
                    result[i].department +
                    "\n" +
                    "Title: " +
                    result[i].jobTitle),
                onTap: () {
                  Navigator.of(context).push(MaterialPageRoute(
                      builder: (context) =>
                          EmployeeDetails(
                              employee: result[i])));
                },
              ),
            );
          });
        ...
    
    

    and search method like

    List<Employee> _search(List<Employee>? employee) {
      if(searchString?.isNotEmpty == true) {
        //search logic what you want
        return employee?.where((element) => element.department.contains(searchString))
            .toList() ?? <Employee>[];
      }
      
      return employee ?? <Employee>[];
    }