alexrindone / flutter_textfield_search

FTFS is a Flutter package which uses a TextField Widget to search and select a value from a list. It's a simple, lightweight, and fully tested package unlike other "autocomplete" or textfield search packages with 100% code coverage.
BSD 2-Clause "Simplified" License
27 stars 33 forks source link

[ERROR:flutter/lib/ui/ui_dart_state.cc(166)] Unhandled Exception: NoSuchMethodError: The method 'toLowerCase' was called on null. #27

Closed ndemeyvan closed 3 years ago

ndemeyvan commented 3 years ago

This is my future to get data

` Future getSearchProduct({@required context,@required String searchItem}) async { try {

  var headerSecond = constant.getHeader(await constant.getAccessToken());
  var response = await http.get(
    "${constant.ApiBaseUrl}/secure/products/search?searchTerm=$searchItem&page=1",
    headers: headerSecond,
  );
  if (response.statusCode == 200) {
    List jsonResponse = json.decode(utf8.decode(response.bodyBytes))['data'];
    print(" 200 response /getSearchProduct : ${jsonResponse}");
      if(jsonResponse.length == 0){
        return [];
      }else {
        List displayableList = new List();
        List secondList = new List();
        for(int i =0 ; i< jsonResponse.length;i++){
          print("Response value : ${jsonResponse[i]['name']}");
          secondList.add({
            'label': jsonResponse[i]['name'],
            'value': jsonResponse[i]['id']
          },);
        }
        for(int i =0 ; i< jsonResponse.length;i++){
          print("Response value : ${jsonResponse[i]['name']}");
          displayableList.add(new OffertIten.fromJson(secondList[i]));
        }
        print("displayList : $displayableList");
        return displayableList;
      }
  } else if (response.statusCode == 401) {
    print("401 reponse getSearchProduct/: ${response.body}");
    constant.deleteAll401OrLogout(context);
  } else {
    print("errorResponse  getSearchProduct/: ${response.body}");
  }
} catch (e) {
  print("$e");
} finally {
  constant.closeDialog(context);
}

} `

This is my OffertClass

` class OffertIten { String label; dynamic value;

OffertIten({ this.label, this.value });

factory OffertIten.fromJson(Map<String, dynamic> json) { return OffertIten( label: json['name'], value: json['id']

);

} }`

And the TextSeachField :

` TextFieldSearch(label: "label", controller: searchForProductController ,future: () { return api.getSearchProduct(context: context, searchItem: searchForProductController.text); },getSelectedValue: (value) { print("The selected Value : $value"); // this prints the selected option which could be an object }

                      ),`
alexrindone commented 3 years ago
// used within a MaterialApp (code shortened)
    MaterialApp(
      home: Scaffold(
      body: TextFieldSearch(
          label: 'label, 
          controller: searchForProductController
          future: () { 
           // your line below here in your example use had api.getSearchProduct...not sure if it's a typo but it should look like this instead
            return getSearchProduct(context: context, searchItem: searchForProductController.text)
          },
          getSelectedValue: (value) {
            print(value);
          }
        )
      ),
    )

Can you try that and let me know if you still are having issues?

alexrindone commented 3 years ago

Here is a example I use for a production app but it's leveraging the provider package for managing state:

class BreweryNameField extends StatefulWidget {
  @override
  _BreweryNameFieldState createState() => _BreweryNameFieldState();
}

class _BreweryNameFieldState extends State<BreweryNameField> {
  String search = '';
  static const BREWERIES_URL = 'https://nubeer.io/api/breweries-search?search=';
  bool isLoading = false;
  List <Brewery> listBreweries = List();

  Future<List> getBreweries() async {
    try {
      List _list = new List();
      // hit the end point using the controller text for search
      await http.get(BREWERIES_URL + Provider.of<AddBeerProvider>(context, listen: false).breweryController.text).then((http.Response response) {
        // create a dynamic map from the response
        Map<String, dynamic> jsonResponse = jsonDecode(response.body);
        // make sure that the response contains breweries
        if (jsonResponse.containsKey("breweries")) {
          // create a list from the json response breweries that we can loop over
          var breweries = jsonResponse["breweries"].toList();
          // loop through the list of breweries and add the name to the empty list
          for (var i=0; i < breweries.length; i++) {
            _list.add(new BreweryOption.fromJson(breweries[i]));
          }
        }
      });
      // return the breweries found from search or the initial empty list
      return _list;
    } catch(e) {
      throw new Exception(e);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Consumer<AddBeerProvider>(
      builder: (context, model, child){
            return TextFieldSearch(
            label: 'Brewery',
            controller: model.breweryController,
            future: () {
              return getBreweries();
            },
            getSelectedValue: (value) {
              model.setBrewery(value);
            },
        );
      },
    );
  }
}
ndemeyvan commented 3 years ago

OK Mr @alexrindone , I try and I come back to you .

ndemeyvan commented 3 years ago

oki Mr @alexrindone i think it's good . oki mr i think it's good. However it would be necessary to replace the example which it finds in the documentation concerning the recovery of the data alive a Future because it is that it is currently, it does not work, the method that you use here above is different from this:

TextFieldSearch (
          label: 'My Label',
          controller: myController // the TextEditController
          future: () {
            return fetchData (); //the list return by the Future<List>
          },
          getSelectedValue: (value) {
            print (value); // this prints the selected option which could be an object
          }
        )

who is in the documentation

alexrindone commented 3 years ago

will do, thank you @ndemeyvan !