Open In App

Flutter Bloc – Basic Search

Last Updated : 30 Mar, 2022
Improve
Improve
Like Article
Like
Save
Share
Report

Flutter is a powerful tool to develop cool android and ios apps and much more like PWAs from a single code base. In this article, we will guide you on how you can design your Bloc architecture for the search module.

GOAL: For starters, we will aim to create an app with a search field that can have consecutive search pages and save all the results.

Prerequisites:

  • Must have a basic knowledge of Business Logic and Global State Management

Let’s get started.

Implementation:

First things first let’s implement a basic Bloc named Search that is creating a bloc file, an event file, states, and a repository to fetch data either locally or remotely.

Dart




import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:medcomp/models/med.model.dart';
 
class SearchEvent extends Equatable {
  @override
  List<Object> get props => [];
}
 
class SearchEventLoadData extends SearchEvent {
  final String str;
  SearchEventLoadData({@required this.str});
}


This is the event file that you would’ve created in the first go after having a basic knowledge of flutter so now what we want you to do is add a list of List of str which will store all the earlier searched phrases or strings. To save your results to save user’s time you can also create a list of your result model to store them in your bloc. Let’s call it List of Result Model. Also, create one more class extending SearchEvent which will be invoked when a particular Result Page will be popped.

Dart




class SearchEventLoadData extends SearchEvent {
  final List strList;
  final List<DataModel> dataList;
  SearchEventLoadData({@required this.strList, @required this.dataList});
}
 
class SearchEventPopSearch extends SearchEvent {}


Since now we have created variables to store our earlier searched items it’s time to implement the states. Here the basic concept is to expose the whole list of data to the viewmodel and render the last element of the list because we are using stack and the last pushed data was the recent search.

Dart




import 'package:equatable/equatable.dart';
 
class SearchState extends Equatable {
  @override
  List<Object> get props => [];
}
 
class SearchStateNotLoaded extends SearchState {}
 
class SearchStateLoading extends SearchState {}
 
class SearchStateLoaded extends SearchState {
  final List<String> strList;
  final List<ResultModel> dataList;
  SearchStateLoaded(this.strList, this.dataList);
}
 
class SearchStateError extends SearchState {
  final message;
  SearchStateError(this.message);
}


Now it’s time to add a bloc file layer to combine these components. We have created a SearchRepo which will be responsible to fetch the data from API or local Databases and let the repo file work normally.

Dart




import 'package:bloc/bloc.dart';
import 'package:medcomp/events/search.event.dart';
import 'package:medcomp/models/search.model.dart';
import 'package:medcomp/repositories/search.repo.dart';
import 'package:medcomp/states/search.state.dart';
 
class SearchBloc extends Bloc<SearchEvent, SearchState> {
  @override
  SearchState get initialState => SearchStateNotLoaded();
 
  SearchRepo _searchRepo = SearchRepo();
 
  @override
  Stream<SearchState> mapEventToState(SearchEvent event) async* {
    if (event is SearchEventLoadData) {
      yield SearchStateLoading();
      try {
        ResultModel resultModel = await this._searchRepo.getDetails(event.strList.last);
        event.dataList.add(resultModel);
        if (search == null) {
          String error = this._searchRepo.message;
          yield SearchStateError(error);
        } else {
          yield SearchStateLoaded(event.strList, event.dataList);
        }
      } catch (e) {
        yield SearchStateError(e);
      }
    }
 
    if (event is SearchEventPopSearch) {
      try {
        if (state is SearchStateLoaded) {
          var oldState = (state as SearchStateLoaded);
          yield SearchStateLoading();
          oldState.strList.removeLast();
          oldState.dataList.removeLast();
          yield SearchStateLoaded(oldState.strList, oldState.dataList);
        } else {
          yield SearchStateError('state is SearchStateLaoded false');
        }
      } catch (e) {
        yield SearchStateError('Error in search remove $e');
      }
    }
  }
}




Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads