Home > Software design >  Pressing on search icon does not display anything on the screen
Pressing on search icon does not display anything on the screen

Time:02-04

I am trying to do a search on food recipes where an API will fetch the recipes and display them on the screen, but whenever I press on search, the food does not appear

Below is my services that handles fetching data from the API

class SearchFoodService {
  static late String foodToBeSearched;
  late int foodTotalNumber;
  List foodIdSearchList = [];
  List foodNameList = [];
  List foodImageList = [];
  List instructionsList = [];
  List foodDurationList = [];
  List foodIdList = [];
  List calories = [];
  List fats = [];
  List carbohydrates = [];
  List proteins = [];

  final String apiKey = '*************************';
  searchFood() async {
    try {
      http.Response response = await http.get(
        Uri.parse(
            'https://api.spoonacular.com/recipes/complexSearch?apiKey=$apiKey&query=$foodToBeSearched&number=1'),
      );
      dynamic foodData = response.body;
      Map data = json.decode(foodData);
      foodTotalNumber = data['number'];
      for (int i = 0; i < foodTotalNumber; i  ) {
        int foodId = data['results'][i]['id'];
        foodIdSearchList.add(foodId);
      }
    } catch (e) {
      print('fetching error');
    }
    for (int i = 0; i < foodIdSearchList.length; i  ) {
      try {
        http.Response response = await http.get(
          Uri.parse(
              'https://api.spoonacular.com/recipes/${foodIdSearchList[i]}/information?apiKey=$apiKey&includeNutrition=true'),
        );
        dynamic foodData = response.body;
        Map data = json.decode(foodData);
        String foodName = data['title'];
        foodNameList.add(foodName);
        String foodImage = data['image'];
        foodImageList.add(foodImage);
        int foodDuration = data['readyInMinutes'];
        foodDurationList.add(foodDuration);
        var foodCalories = data['nutrition']['nutrients'][0]['amount'];
        var foodCarbs = data['nutrition']['nutrients'][3]['amount'];
        var foodFat = data['nutrition']['nutrients'][1]['amount'];
        var foodProtein = data['nutrition']['nutrients'][9]['amount'];
        String foodInstruction = data['instructions'];
        instructionsList.add(foodInstruction);
        calories.add(foodCalories);
        carbohydrates.add(foodCarbs);
        fats.add(foodFat);
        proteins.add(foodProtein);
      } catch (p) {
        print('p ---> $p');
      }
    }

    return [
      foodNameList,
      foodImageList,
      foodDurationList,
      calories,
      carbohydrates,
      fats,
      proteins,
      instructionsList,
    ];
  }
}

Below is the search bar where I have a TextEditingcontroller

bool textInBar = false;

class SearchBar extends StatefulWidget {
  const SearchBar({
    Key? key,
  }) : super(key: key);

  @override
  State<SearchBar> createState() => _SearchBarState();
}

class _SearchBarState extends State<SearchBar> {
  final textItem = TextEditingController();
  @override
  Widget build(BuildContext context) {
    return TextField(
      controller: textItem,
      style: constants.TextStyles.subTitle,
      cursorColor: Colors.black54,
      decoration: InputDecoration(
        suffixIcon: IconButton(
          onPressed: () {
            textInBar = true;
            setState(() {
              SearchFoodService.foodToBeSearched = textItem.text;
            });
          },
          icon: const Icon(
            Icons.search,
            color: Colors.black54,
            size: 35,
          ),
        ),
        hintText: 'Search any recipe',
        hintStyle: constants.TextStyles.title
            .copyWith(fontSize: 20, color: Colors.black),
        fillColor: const Color(0xFFf2f2f2),
        filled: true,
        enabledBorder: OutlineInputBorder(
          borderSide: const BorderSide(
            color: Color(0xFFf2f2f2),
            width: 0,
          ),
          borderRadius: BorderRadius.circular(25),
        ),
        focusedBorder: OutlineInputBorder(
          borderSide: const BorderSide(width: 0, color: Color(0xFFf2f2f2)),
          borderRadius: BorderRadius.circular(25),
        ),
      ),
    );
  }
}

And finally below is the screen which is to display the items on the screen

class SearchScreen extends StatefulWidget {
  static String id = 'search_screen';
  showContent() {
    return Expanded(
      child: FutureBuilder(
        future: SearchFoodService().searchFood(),
        builder: (context, dynamic snapshot) {
          if (snapshot.hasData) {
            List recipeName = snapshot.data[0] ?? [];
            List images = snapshot.data[1] ?? [];
            List foodDuration = snapshot.data[2] ?? [];
            List foodCalories = snapshot.data[3] ?? [];
            List foodCarbs = snapshot.data[4] ?? [];
            List foodFat = snapshot.data[5] ?? [];
            List foodProteins = snapshot.data[6] ?? [];
            List foodInstruction = snapshot.data[7] ?? [];
            return GridView.builder(
              gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
                crossAxisCount: 2,
                crossAxisSpacing: 15,
                childAspectRatio: 0.65,
              ),
              itemBuilder: (context, index) {
                return FoodContainer(
                  foodLabel: recipeName[index],
                  foodImage: images[index],
                  time: foodDuration[index],
                  onPressed: () {
                    Navigator.push(
                      context,
                      MaterialPageRoute(
                        builder: (context) => FoodScreen(
                          foodName: recipeName[index],
                          image: images[index],
                          foodTime: foodDuration[index],
                          calories: foodCalories[index],
                          protein: foodProteins[index],
                          carbs: foodCarbs[index],
                          fat: foodFat[index],
                          foodInstructions: foodInstruction[index],
                        ),
                      ),
                    );
                  },
                );
              },
            );
          } else if (snapshot.hasError) {
            return const Text('Error');
          } else {
            return const Align(child: CircularProgressIndicator());
          }
        },
      ),
    );
  }

  const SearchScreen({Key? key}) : super(key: key);

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

class _SearchScreenState extends State<SearchScreen> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Column(
          children: [
            const Padding(
              padding: EdgeInsets.only(top: 8.0, left: 15, right: 15),
              child: SearchBar(),
            ),
            textInBar == false ? Text('Search') : widget.showContent(),
          ],
        ),
      ),
    );
  }
}

Whenever I put a food recipe, for example pizza, in place of the foodToBeSearched in the services file, the food loads automatically after hot reloading. That means maybe there might be a problem with the algorithm for assigning foodToBeSearch = textItem.text;.

CodePudding user response:

This code:

setState(() {
  SearchFoodService.foodToBeSearched = textItem.text;
});

will not force a new build, since the build method of your StatefulWidget does not use this variable. SearchFoodService class uses it, but that is not a widget class, so setState will have no effect.

I would suggest to add the search term to your State<SearchScreen> class:

String? _foodToBeSearched;

Then use this member in the future. You have to move the FutureBuilder to the State<SearchScreen> class, and use for example like this:

future: SearchFoodService().searchFood(_foodToBeSearched),

And your setState should set this member:

setState(() {
  _foodToBeSearched = textItem.text;
});

This will rebuild the widget, and the future will be executed using the entered search term as parameter.

  •  Tags:  
  • Related