Previously we have covered BLoC http get request. Now we do post request here.
Flutter BLoC http post request example. Using bloc post request could be scary for beginners. Here I have covered in detail about post request.
First create a repository. This repository would connect to the server and post data. This is where you should put your endpoint.
I am using firebase for end point.
class ProductRepository {
final _fireCloud = FirebaseFirestore.instance.collection("products");
Future<void> create({required String name, required String price}) async {
try {
await _fireCloud.add({"name": name, "price": price});
} on FirebaseException catch (e) {
if (kDebugMode) {
print("Failed with error '${e.code}': ${e.message}");
}
} catch (e) {
throw Exception(e.toString());
}
}
}
Then we will create events and states. Most of the time in BLoC events and states are represented using classes. So we will create class.
We also have to know that, from UI using bloc we will call events. Events will trigger states. States will trigger new UI or update UI.
Below is our event class
abstract class ProductEvent extends Equatable {
@override
List<Object> get props => [];
}
class Create extends ProductEvent {
final String name;
final String price;
Create(this.name, this.price);
}
After that we will create states. For each new update of UI you should have a state dedicated for them. If you have five UI updates then you have five states or five classes.
@immutable
abstract class ProductState extends Equatable {}
class InitialState extends ProductState{
@override
// TODO: implement props
List<Object?> get props => [];
}
class ProductAdding extends ProductState {
@override
List<Object?> get props => [];
}
class ProductAdded extends ProductState{
@override
List<Object?> get props =>[];
}
class ProductError extends ProductState {
final String error;
ProductError(this.error);
@override
List<Object?> get props => [error];
}
Now it’s time to combine events and states and make a bloc. Events would be called from inside bloc.
Actually blocs are used to register events. Our newly created bloc will extend BLoC library.
class ProductBloc extends Bloc<ProductEvent, ProductState> {
final ProductRepository productRepository;
ProductBloc({required this.productRepository}) : super(InitialState()) {
on<Create>((event, emit) async {
emit(ProductAdding());
await Future.delayed(const Duration(seconds: 1));
try {
await productRepository.create(
name: event.name, price: event.price);
emit(ProductAdded());
} catch (e) {
emit(ProductError(e.toString()));
}
});
}
}
As the events are registered inside bloc, the states are also triggered inside the bloc.
Since our blocs are ready we can now inject them in your UI.
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
home: RepositoryProvider(
create: (context) => ProductRepository(),
child: const Home(),
)
);
}
}
class Home extends StatelessWidget {
const Home({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey<ScaffoldState>();
return BlocProvider(
create: (context) => ProductBloc(
productRepository:RepositoryProvider.of<ProductRepository>(context)
),
child: Scaffold(
key: scaffoldKey,
body: BlocListener<ProductBloc, ProductState>(
listener: (context, state) {
if (state is ProductAdded) {
ScaffoldMessenger.of(context)
.showSnackBar(const SnackBar(content: Text("Product added"), duration: Duration(seconds: 2),));
}
},
child: BlocBuilder<ProductBloc, ProductState>(
builder: (context, state) {
if (state is ProductAdding) {
return const Center(
child: CircularProgressIndicator(),
);
}else if(state is ProductError){
return const Center(child:Text("Error"));
}
return const HomePage();
},
)
)
),
);
}
}
We are using BlocProvider to inject blocs and using RepositoryProvider to inject repository that we created early.
Now we would be able find our blocs from UI. Because injection is done.
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
// text fields' controllers
final TextEditingController _nameController = TextEditingController();
final TextEditingController _priceController = TextEditingController();
Future<void> _create() async {
await showModalBottomSheet(
isScrollControlled: true,
context: context,
builder: (BuildContext ctx) {
return Padding(
padding: EdgeInsets.only(
top: 20,
left: 20,
right: 20,
bottom: MediaQuery.of(ctx).viewInsets.bottom + 20),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextField(
controller: _nameController,
decoration: const InputDecoration(labelText: 'Name'),
),
TextField(
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
controller: _priceController,
decoration: const InputDecoration(
labelText: 'Price',
),
),
const SizedBox(
height: 20,
),
ElevatedButton(
child: const Text('Create'),
onPressed: () async {
final String name = _nameController.text;
final double? price =
double.tryParse(_priceController.text);
if (price != null) {
_postData(context);
_nameController.text = '';
_nameController.text = '';
Navigator.of(context).pop();
}
},
)
],
),
);
});
}
void _postData(context) {
BlocProvider.of<ProductBloc>(context).add(
Create(_nameController.text, _priceController.text),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Center(child: Text('Firebase Firestore')),
),
floatingActionButton: FloatingActionButton(
onPressed: () => _create(),
child: const Icon(Icons.add),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat
);
}
}
Where to go from here
You can use the firebase flutter tutorial with BLoC. Previously we have used Getx to do it.
You can also use firebase crud tutorial using BLoC