Previously we use http.get for loading data with Provider State Management
Here we will see how to use flutter Provider state management to do a http post request. Here we will acheive three things
1. Load restful api data from server using Provider
2. Notify the UI about the loaded data using Provider
3. Redirect the user to a new page using Provider
Signup model
The above picture helps us build our data model.
signup_model.dart
class SignUpBody{
String name;
String phone;
String email;
String password;
SignUpBody({
required this.name,
required this.phone,
required this.email,
required this.password
});
Map<String, dynamic> toJson(){
final Map<String, dynamic> data = <String, dynamic>{};
data["f_name"] = name;
data["phone"] = phone;
data['email'] = email;
data['password'] = password;
return data;
}
}
Here we used four fields to build our data model. We have a constructor which will convert object to Json before we send it to the server.
Service class
We need to create service or service class, to post data to the network or server using. We are using a restful api here to do it.
This service class contains only one method. It's name is regsiter class. Inside this method we call http.post method to send the info from the user and other related network information.
service_class.dart
import 'dart:convert';
import 'dart:developer';
import 'dart:io';
import 'package:http/http.dart' as http;
import 'package:provider_post_request/signup_model.dart';
Future<http.Response?> register(SignUpBody data) async {
http.Response? response;
try {
response =
await http.post(
Uri.parse("http://127.0.0.1:8000/api/v1/auth/register"),
headers: {
HttpHeaders.contentTypeHeader: "application/json",
},
body: jsonEncode(data.toJson()));
} catch (e) {
log(e.toString());
}
return response;
}
In the above code http.post takes three parameters
√ Uri: for pointing to server and end point
√ headers: for protocol and data type
√ body: for sending the actual data
Regardless whatever the response we get back from the server, we just return it and check in DataClass(below). We have use jsonEncode() and toJson() to make sure that we are sending json to the server.
Data class (Provider)
This is another important class. Here the state management magic happens. This class extends ChangeNotifier and holds two variables.
√ loading: using this variable we know when the data is loaded.
√ isBack: for a call back function. If statuscode is 200 then we set it to true
data_class.dart
import 'package:flutter/cupertino.dart';
import 'package:http/http.dart' as http;
import 'package:provider_post_request/service_class.dart';
import 'package:provider_post_request/signup_model.dart';
class DataClass extends ChangeNotifier {
bool loading = false;
bool isBack = false;
Future<void> postData(SignUpBody body) async {
loading = true;
notifyListeners();
http.Response response = (await register(body))!;
if (response.statusCode == 200) {
isBack = true;
}
loading = false;
notifyListeners();
}
}
We also used notifyListeners() to let the UI about the changes happened here.
Provider entry point
Entry point of this app is main() method. Here we have used MultiProvider since, in future you can multiple providers in your app. Right now you only have one provider(DataClass).
Code for main.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:provider_post_request/sing_up.dart';
import 'data_class.dart';
void main() {
runApp(MultiProvider(providers: [
ChangeNotifierProvider(create: (_)=>DataClass()),
],
child:const MyApp()));
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return
MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const ProviderDemoScreen(),
);
}
}
class ProviderDemoScreen extends StatefulWidget {
const ProviderDemoScreen({Key? key}) : super(key: key);
@override
_ProviderDemoScreenState createState() => _ProviderDemoScreenState();
}
class _ProviderDemoScreenState extends State<ProviderDemoScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[300],
appBar: AppBar(
title: const Text("Provider Demo"),
),
body: Center(
child: GestureDetector(
onTap: (){
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SignUpPage()),
);
},
child: Center(
child: Container(
height: 70,
padding: const EdgeInsets.symmetric(horizontal: 40,vertical: 20),
margin: const EdgeInsets.only(left: 40, right: 40),
child: const Text("Go to Singup page", style: TextStyle(
fontSize: 20,
color: Color(0xFF74beef),
),),
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(15),
boxShadow: const [
BoxShadow(
color: Colors.grey,
offset: Offset(4, 4),
blurRadius: 15,
spreadRadius: 1,
),
BoxShadow(
color: Colors.white,
offset: Offset(-4, -4),
blurRadius: 15,
spreadRadius: 1,
),
]
),
),
),
),
),
);
}
}
Signup page using provider
Sign up page get the provider using Provider.of<DataClass>(context, listen:false). Once you have the provider instance, you can retreive the provider properties(loading and isBack).
Inside sign up page, the register() method gets the provider instance and access the properties.
Here we also call the postData method by sending the object, which triggers a call to the server. Before we can send the data through the postData() method, created an object using SignUpBody model class.
The posting animation also gets starter inside this class. Based on boolean loading
It changes it states from false->true->false
This is where provider notifies the consumer(UI) that, the app internal state has been changed.
sign_up.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:provider/provider.dart';
import 'package:provider_post_request/signup_model.dart';
import 'app_text_field.dart';
import 'data_class.dart';
import 'home_page.dart';
class SignUpPage extends StatelessWidget {
const SignUpPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
var emailController = TextEditingController();
var passwordController = TextEditingController();
var nameController = TextEditingController();
var phoneController = TextEditingController();
Future<void> _registration() async {
String name = nameController.text.trim();
String phone = phoneController.text.trim();
String email = emailController.text.trim();
String password = passwordController.text.trim();
SignUpBody signUpBody = SignUpBody(
name: name, phone: phone, email: email, password: password);
var provider = Provider.of<DataClass>(context, listen: false);
await provider.postData(signUpBody);
if (provider.isBack) {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => HomePage()),
);
}
}
return Scaffold(
backgroundColor: Colors.grey[300],
body: Consumer<DataClass>(builder: (context, data, child) {
return data.loading
? Center(
child: Container(
child: SpinKitThreeBounce(
itemBuilder: (BuildContext context, int index) {
return DecoratedBox(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: index.isEven ? Colors.red : Colors.green,
),
);
},
),
),
)
: SingleChildScrollView(
physics: BouncingScrollPhysics(),
child: Column(
children: [
SizedBox(height: 100),
//app logo
Container(
height: 100,
child: Center(
child: CircleAvatar(
backgroundColor: Colors.grey[300],
radius: 80,
),
)),
//your email
AppTextField(
textController: emailController,
hintText: "Email",
icon: Icons.email),
const SizedBox(
height: 20,
),
//your password
AppTextField(
textController: passwordController,
hintText: "Password",
icon: Icons.password_sharp,
isObscure: true),
SizedBox(
height: 20,
),
//your name
AppTextField(
textController: nameController,
hintText: "Name",
icon: Icons.person),
SizedBox(
height: 20,
),
//your phone
AppTextField(
textController: phoneController,
hintText: "Phone",
icon: Icons.phone),
SizedBox(
height: 20 + 20,
),
//sign up button
GestureDetector(
onTap: () {
_registration();
},
child: Container(
height: 70,
padding: const EdgeInsets.symmetric(
horizontal: 40, vertical: 23),
margin: const EdgeInsets.only(left: 40, right: 40),
child: const Text(
"Sign up",
style: TextStyle(
fontSize: 20,
color: Color(0xFF74beef),
),
),
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(15),
boxShadow: const [
BoxShadow(
color: Colors.grey,
offset: Offset(4, 4),
blurRadius: 15,
spreadRadius: 1,
),
BoxShadow(
color: Colors.white,
offset: Offset(-4, -4),
blurRadius: 15,
spreadRadius: 1,
),
]),
),
),
SizedBox(
height: 10,
),
//tag line
RichText(
text: TextSpan(
text: "Have an account already?",
style: TextStyle(
color: Colors.grey[500], fontSize: 20))),
SizedBox(
height: MediaQuery.of(context).size.height * 0.05,
),
//sign up options
RichText(
text: TextSpan(
text:
"Sign up using one of the following methods",
style: TextStyle(
color: Colors.grey[500], fontSize: 16))),
],
),
);
}));
}
}
Code for app text field
app_text_field.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class AppTextField extends StatelessWidget {
final TextEditingController textController;
final String hintText;
final IconData icon;
bool isObscure;
AppTextField({Key? key,
required this.textController,
required this.hintText,
required this.icon,
this.isObscure=false}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
margin:EdgeInsets.only(left: 20, right: 20),
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(15),
boxShadow: [
const BoxShadow(
color: Colors.grey,
offset: Offset(4, 4),
blurRadius: 15,
spreadRadius: 1,
),
const BoxShadow(
color: Colors.white,
offset: Offset(-4, -4),
blurRadius: 15,
spreadRadius: 1,
),
]
),
child: TextField(
obscureText: isObscure?true:false,
controller: textController,
decoration: InputDecoration(
fillColor: Colors.grey[300],
filled: true,
//hintText,
hintText: hintText,
// prefixIcon
prefixIcon: Icon(icon, color:Colors.yellow),
//focusedBorder
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(15),
borderSide: const BorderSide(
width: 0.0,
color:Colors.white,
)
),
//enabled Border
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(15),
borderSide: const BorderSide(
width: 0.0,
color:Colors.white,
)
),
// enabledBorder
//
// border
border:OutlineInputBorder(
borderRadius: BorderRadius.circular(15),
)
),
),
);
}
}
Code for home page
home_page.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[300],
appBar: AppBar(
title: Text("Provider Demo"),
),
body: Center(
child: GestureDetector(
child: Center(
child: Container(
height: 70,
padding: const EdgeInsets.symmetric(horizontal: 40,vertical: 20),
margin: const EdgeInsets.only(left: 40, right: 40),
child: const Center(
child: Text("Home page", style: TextStyle(
fontSize: 20,
color: Color(0xFF74beef),
),),
),
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(15),
boxShadow: const [
BoxShadow(
color: Colors.grey,
offset: Offset(4, 4),
blurRadius: 15,
spreadRadius: 1,
),
BoxShadow(
color: Colors.white,
offset: Offset(-4, -4),
blurRadius: 15,
spreadRadius: 1,
),
]
),
),
),
),
),
);
}
}