Posted in API Dart Flutter PHP & MySQL

Flutter – How to make Search Bar, Show suggestions by PHP and MySQL

Flutter – How to make Search Bar, Show suggestions by PHP and MySQL Posted on May 19, 2020Leave a comment
I'm Hari Prasad Chaudhary from Nepal, developer of the finest educational website/app "MeroSpark" and the finest eCommerce system "PasalaY". Here I share the code snippet which I learn during development.

In this example, I have made a search bar which is appeared when the “Search” icon gets clicked at App Bar. When a user inputs any query, it gets the suggestion from PHP and MySQL server and shows in the app. I have used REST API to communicate with the server.

search suggestion

Back end (Server side Part): Our MySQL table

This is our MySQL database table where the name, address, class, and roll_no are stored. Now in the PHP part, we will list all the data in an array, match every full_name with a query, and sort according to the matching percentage of full_name and query from the app. See the PHP code below:

test/search_suggestion.php (See the comments in code)

<?php 
  $db = "test_db";
  $host = "localhost";
  $db_user = 'root';
  $db_password = 'root';
  //MySql server and database info
  
  $link = mysqli_connect($host, $db_user, $db_password, $db);
  //connecting to database

  function matchper($s1, $s2){ 
        similar_text(strtolower($s1), strtolower($s2), $per);
        return $per; //function to find matching similarity of two string
  }

  if(isset($_REQUEST["query"])){
      $query = strtolower($_REQUEST["query"]);
  }else{
      $query = "";
  } //if there is query in parameter then grabe it


  $json["error"] = false;
  $json["errmsg"] = "";
  $json["data"] = array();

  $sql = "SELECT * FROM student_list ORDER BY full_name ASC";
  $res = mysqli_query($link, $sql);
  $numrows = mysqli_num_rows($res);
  if($numrows > 0){
     //check if there is any data
     $namelist = array();

      while($obj = mysqli_fetch_object($res)){
           $matching = matchper($query, $obj->full_name);
           //get the similarity between name and query
           $namelist[$matching][$obj->student_id] = $obj->full_name;
           //set the matching and student id as key so that we can sort according to key
      }

      krsort($namelist); 
      //to sort array by key in desending order, use ksort() to reverse

      foreach($namelist as $innerarray){
         foreach($innerarray as $studentid => $fullname){
            $subdata = array(); //create new array
            $subdata["id"] = "$studentid"; //return as string
            $subdata["name"] = $fullname; 

            array_push($json["data"], $subdata); //push sub array into $json array
         }
      }
  }else{
      $json["error"] = true;
      $json["errmsg"] = "No any data to show.";
  }

  mysqli_close($link);
  
  header('Content-Type: application/json');
  // tell browser that its a json data
  echo json_encode($json);

?>

Now in the Flutter part, add http package as a dependency by adding following line in pubspec.yaml file.

dependencies:
  flutter:
    sdk: flutter
  http: ^0.12.1

Add Internet Permission by adding this line in android/app/src/main/AndroidManifest.xml before <application>

<uses-permission android:name="android.permission.INTERNET"/>

Flutter Dart Code, see explanation in comments to understand the code.

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:http/http.dart' as http;
//import http package manually

class SearchBar extends StatefulWidget{
  @override
  State<StatefulWidget> createState() {
     return _SearchBar();
  }
}

class _SearchBar extends State<SearchBar>{
  bool searching, error;
  var data;
  String query;
  String dataurl = "http://192.168.0.112/test/search_suggestion.php";
  // do not use http://localhost/ , Android emulator do not recognize localhost
  // insted use your local ip address or your live URL
  // hit "ipconfig" on Windows or "ip a" on Linux to get IP Address

  @override
  void initState() {
        searching = false;
        error = false;
        query = "";
        super.initState();
  }

  void getSuggestion() async{  //get suggestion function
        var res = await http.post(dataurl + "?query=" + Uri.encodeComponent(query));
        //in query there might be unwant character so, we encode the query to url
        if (res.statusCode == 200) {
            setState(() {
                data = json.decode(res.body);
                //update data value and UI
            });
        }else{
           //there is error
           setState(() {
               error = true;
           });
        }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
         appBar: AppBar( 
            leading: searching?IconButton( 
                              icon:Icon(Icons.arrow_back),
                              onPressed:(){
                                  setState(() {
                                     searching = false;
                                     //set not searching on back button press
                                  });
                              },
                            ):Icon(Icons.play_arrow),
            //if searching is true then show arrow back else play arrow
            title:searching?searchField():Text("My Frieds"),
            actions: <Widget>[
                 IconButton(
                   icon: Icon(Icons.search),
                   onPressed:(){
                        setState(() {
                             searching = true;
                        });
                    }
                 ), // search icon button

                 //add more icons here
            ],
            backgroundColor: searching?Colors.orange:Colors.deepOrange,
            //if searching set background to orange, else set to deep orange
         ),

         body:SingleChildScrollView( 
             child:Container( 
                alignment: Alignment.center,
                child:data == null?
                      Container(
                         padding: EdgeInsets.all(20),
                         child: searching?Text("Please wait")
                                :Text("Search any peoples")
                        //if is searching then show "Please wait"
                        //else show search peopels text
                      ):
                      Container( 
                        child: searching?showSearchSuggestions()
                               :Text("Find any Peoples"),
                      )
                  // if data is null or not retrived then 
                  // show message, else show suggestion
             )
         )
    );
  }

  Widget showSearchSuggestions(){
     List<SearchSuggestion> suggestionlist = List<SearchSuggestion>.from(
        data["data"].map((i){
            return SearchSuggestion.fromJSON(i);
        })
     );
              //serilizing json data inside model list.
     return Column(
       children:suggestionlist.map((suggestion){
           return InkResponse( 
             onTap: (){
                //when tapped on suggestion
                print(suggestion.id); //pint student id
             },
             child: SizedBox( 
               width:double.infinity, //make 100% width
                  child:Card( 
                        child: Container( 
                            padding: EdgeInsets.all(15),
                            child: Text(suggestion.name, style: TextStyle(
                                fontSize:20, fontWeight:FontWeight.bold,
                            ),),
                        ),
                  )
             )
           );
       }).toList(),
     );
  }

  Widget searchField(){ //search input field
      return Container( 
         child:TextField(
           autofocus: true,
            style: TextStyle(color:Colors.white, fontSize: 18),
            decoration:InputDecoration( 
                 hintStyle: TextStyle(color:Colors.white, fontSize: 18),
                 hintText: "Search Peoples",
                 enabledBorder: UnderlineInputBorder(
                     borderSide: BorderSide(color:Colors.white, width:2),
                 ),//under line border, set OutlineInputBorder() for all side border
                 focusedBorder: UnderlineInputBorder(
                     borderSide: BorderSide(color:Colors.white, width:2),
                 ), // focused border color
            ), //decoration for search input field
            onChanged: (value){
                  query = value; //update the value of query 
                  getSuggestion(); //start to get suggestion
            },
         )
      );
  }
}


//serarch suggestion data model to serialize JSON data 
class SearchSuggestion{
   String id, name;
   SearchSuggestion({this.id, this.name});
   
   factory SearchSuggestion.fromJSON(Map<String, dynamic> json){
      return SearchSuggestion( 
        id: json["id"],
        name: json["name"],
      );
   }
}

In this way, you can make Search Bar with a suggestion feature using PHP and MySQL server.

I'm Hari Prasad Chaudhary from Nepal, developer of the finest educational website/app "MeroSpark" and the finest eCommerce system "PasalaY". Here I share the code snippet which I learn during development.

Leave a Reply

Your email address will not be published. Required fields are marked *