Flutter Provider Http Post Request Example With Loading Animation

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

flutter provider post request

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,
                    ),

                  ]
              ),
            ),
          ),
        ),
      ),
    );
  }
}

Recent posts