0
votes

I have a Stateful Class that build a grid if Items. This items are retrieved by an HTTP call to an external server.

I am Using PagewiseGridView (https://pub.dartlang.org/packages/flutter_pagewise) to create my grid.

PagewiseGridView has a parameter called totalCount that is an INT, and it works perfectly when I get the totals from a Future because I've set an INT var inside initstate() to change the value after returning the Future.

The real problem is when I do a search on my external server. For the search I am building a class: ShowSearch extends SearchDelegate and Search delegate has widget called buildResult that will show the results that I get from my external call.

I am also using PagewiseGridView to build my results layout.

Here's the code:

@override
Widget buildResults(BuildContext context) {
  // TODO: implement buildResults
  return PagewiseGridView(
    pageSize: 10,
    totalCount: BackendService.getSearchTotals(query),
    crossAxisCount: 2,
    mainAxisSpacing: 10.0,
    crossAxisSpacing: 5.0,
    //childAspectRatio: 0.802,
    padding: EdgeInsets.all(5.0),
    itemBuilder: _itemBuilder,
    pageFuture: (pageIndex){
      return BackendService.getSearchItems(pageIndex, query);
    },
  );
}

"totalCount: BackendService.getSearchTotals(query)" returns a Future, so it does not work because it requires an INT (totalCount: 100, works).

How can I solve this?

FULL CLASS (Different Method):

class ShowSearch extends SearchDelegate<BackendService> {
  Color _mainColor = const Color(0xFFCA0813);
  int _searchTotalCounter;

  @override
  void initState() {
    //super.initState();
    getSearchTotalCounter();
  }

  void getSearchTotalCounter() async {
    _searchTotalCounter = await getSearchTotals(query);

    //setState(() {});
  }

  Future<int> getSearchTotals(query) async {
    var myRes = await http.get(Uri.encodeFull("https://www.mydomain.io/wp-json/test/v1/stats/search/?s=$query"), headers: {"Accept": "application/json"});
    var myResBody = json.decode(myRes.body);

    return myResBody["count_total"];
  }

  @override
  List<Widget> buildActions(BuildContext context) {
    // TODO: implement buildActions
    return [IconButton(
      icon: Icon(Icons.clear),
      onPressed: (){
        query = "";
      }
    )];
  }

  @override
  Widget buildLeading(BuildContext context) {
    // TODO: implement buildLeading
    return IconButton(icon: Icon(Icons.arrow_back), onPressed: (){
      close(context, null);
    });
  }

  @override
  Widget buildSuggestions(BuildContext context) {
    // TODO: implement buildSuggestions
    return Column(
      children: <Widget>[
        Padding(
          padding: EdgeInsets.all(10.0),
          child: Center(
              child: Text(query)
          )
        )
      ],
    );
  }

  @override
  Widget buildResults(BuildContext context) {
    // TODO: implement buildResults
    return PagewiseGridView(
        pageSize: 10,
        totalCount: _searchTotalCounter,
        //totalCount: 20 //IT WORKS!
        crossAxisCount: 2,
        mainAxisSpacing: 10.0,
        crossAxisSpacing: 5.0,
        //childAspectRatio: 0.802,
        padding: EdgeInsets.all(5.0),
        itemBuilder: _itemBuilder,
        pageFuture: (pageIndex){
          return BackendService.getSearchItems(pageIndex, query);
        },
    );
  }
}

I've commented super.initState() and setState() because are giving an error (error: The method 'initState' isn't defined in a superclass of 'SearchDelegate'.) and (error: The method 'setState' isn't defined for the class 'ShowSearch'.).

https://www.mydomain.io/wp-json/test/v1/stats/search/?s=$query

returns

{"status":"ok","total":10,"count_total":502,"pages":51,"query":"beans"}
1
Use a FutureBuilder for BackendService.getSearchTotals(query) and then build PagewiseGridView in this builder. - Günter Zöchbauer
You can also call BackendService.getSearchTotals(query) in initState and store the result in a field for later use in build, but you can't use await in initState to get the value out of the Future so you would need to move the call to BackendService.getSearchTotals(query) to another method where you use async/await that you then call from initState. That sounds a bit cumbersome, but if the logic to get the value is a bit more complex than a single function call, then it might make sense. - Günter Zöchbauer
can You please explain the last option, because I tried that way and I cannot setState inside the new method. - Raffaele Colleo
It would be great if you could post your code that didn't work and then we can discuss how to fix it. - Günter Zöchbauer
You mean with the initState()? - Raffaele Colleo

1 Answers

1
votes

first you can add totalCount: count, and set count to 0 then call this getCount() method mentioned here what will happen , first BackendService.getSearchTotals(query) will be called and when it finishes it will return a future, then you can use the result
to update the count and rebuild using setState , ps:you can show a circular loader while the getCount is working.

Future getCount() async {
       //here you can call the function and handle the output(return value) as result
           BackendService.getSearchTotals(query).then((result) {
               // print(result);
               setState(() {
                  //handle your result here and update the count.
                  //update build here.
               });
          }).catchError(handleError);//you can call handleError method show an alert or to try again
     }