Skip to main content

Form

Pada Tahapan Ini, kita akan coba membahas beberapa point:

  • Akan coba membuat beberapa inputan menjadi sebuah form
  • Melakukan validasi inputan
  • Memproses Data Inputan
  • Akan menggunakan Provider untuk menampung dan menampilkan data di berbagai widget

Requirement

Ada beberapa hal yang perlu diperhatikan sebelum lanjut:

Struktur Folder

Kita akan membuat struktur folder dan file seperti berikut:

alt

Silahkan Buat Terlebih dahulu !

Layar Awal

Konsep Login
  • Buat Stateful Widget (karna butuh mengelola state dari form)
  • Define Variable yang dibutuhkan
  • Mencoba memecah Widget Form menjadi component kecil
  • Lakukan Validasi
  • Panggil Function / Gunakan method yang dibuat di Auth Provider
    • Pass argument nya berupa data yang telah input dari form
  • Navigasi ke halaman Home Jika Telah Submit
lib/screens/login.dart
import 'package:flutter/material.dart';class Login extends StatefulWidget {  const Login({Key? key}) : super(key: key);    State<Login> createState() => _LoginState();}class _LoginState extends State<Login> {  // Pada Line ini kita akan membuat form-form kecil yang akan kita panggil nanti, dan  // Pembuatan beberapa variable, serta  // Pembuatan Method atau function    Widget build(BuildContext context) {    return Scaffold(      appBar: AppBar(        title: const Text('Login'),      ),      resizeToAvoidBottomInset: false,      body: Center(        child: Padding(          padding: const EdgeInsets.all(15),          child:  SingleChildScrollView(            child: Form(              // Pada Line Ini kita akan memanggil form-form kecil yang kita buat            ),          )        ),      )    );  }}

Konsep Home

Menggunakan Stateless Widget (Karna Hanya akan mengambil data dari Auth Provider)

lib/screens/home.dart
import 'package:flutter/material.dart';class Home extends StatelessWidget {  const Home({Key? key}) : super(key: key);    Widget build(BuildContext context) {    // Pada Line ini kita akan memanggil data dari provider untuk disimpan ke variable local    return Scaffold(      appBar: AppBar(        title: const Text('Home'),      ),      body: Center(        child: Column(          mainAxisAlignment: MainAxisAlignment.center,          children: [            const Text('Welcome !'),            // Pada Line ini kita akan menampilkan data dari variable yang berasal dari provider            ElevatedButton(              onPressed: () {                Navigator.pushNamed(                  context,                   '/profile'                );              },               child: const Text('See My Profile'),            )          ],        ),      ),    );  }}

Konsep Profile

Menggunakan Stateless Widget (Karna Hanya akan mengambil data dari Auth Provider)

lib/screens/profile.dart
import 'package:belajar_form/providers/auth.dart';import 'package:flutter/material.dart';import 'package:provider/provider.dart';class Profile extends StatelessWidget {  const Profile({Key? key}) : super(key: key);    Widget build(BuildContext context) {    // Pada Line ini kita akan memanggil data dari provider untuk disimpan ke variable local        return Scaffold(      appBar: AppBar(        title: const Text('Profile'),      ),      body: Center(        child: Padding(          padding: const EdgeInsets.all(14),          child: Column(            mainAxisAlignment: MainAxisAlignment.center,            children: <Widget>[              const Text('Halaman Profile Nih !'),              // Pada Line ini kita akan menampilkan data dari variable yang berasal dari provider            ],          ),        )      ),    );  }}

Model

Ini Berperan untuk mendefinisikan bentuk data yang akan digunakan.

User

Kita akan mengelola data yang berkaitan dengan user, akan kita berikan nama file user.dart

lib/model/user.dart
class UserModel {  // Define Variable  String name;  String email;  String gender;  bool isMarried;  List skills;  // Define Constructor  UserModel({    required this.name,    required this.email,    required this.gender,    required this.isMarried,    required this.skills  });}

Provider

Ini Berperan untuk mengelola state dalam aplikasi.

Auth

Kita akan menggunakan provider ini untuk mengelola data terkait autentikasi

Catatan

Dalam materi kali ini hanya akan simulasi saja terkait autentikasinya

Langkah
  • Define variable yang dibutuhkan
    • Mendefinisikan dengan Class “UserModel” yang dibuat sebelumnya
    • dengan Tipe “Late” → untuk di inisialisasikan nanti saat runtime dan bukan saat compile
  • Buat Getter untuk data yang diinginkan
  • Buat function yang dibutuhkan
    • mengambil data dari parameter
lib/providers/auth.dart
import 'package:belajar_form/models/user.dart';import 'package:flutter/material.dart';class AuthProvider extends ChangeNotifier {    // Inisiasikan Data User  late UserModel _user;  // Buat Getter  UserModel get user => _user;  // Buat Function simulasi Login  void simulateLogin(Map<String, dynamic> formData) {    _user = UserModel(      name: formData['name'],       email: formData['email'],       gender: formData['gender'],       isMarried: formData['isMarried'],       skills: formData['skills']    );    notifyListeners();  }  }

Entry Point

Pada langkah kali ini, kita akan memodifikasi main.dart kita
Untuk menggunakan Provider yang telah kita buat.

lib/main.dart
import 'package:belajar_flutter/providers/auth.dart';import 'package:belajar_flutter/screens/home.dart';import 'package:belajar_flutter/screens/login.dart';import 'package:belajar_flutter/screens/profile.dart';import 'package:flutter/material.dart';import 'package:provider/provider.dart';void main() {  runApp(const MyApp());}class MyApp extends StatelessWidget {  const MyApp({Key? key}) : super(key: key);  // This widget is the root of your application.    Widget build(BuildContext context) {    return MultiProvider(      providers: [        ChangeNotifierProvider(create: (context) => AuthProvider())      ],      child: MaterialApp(        title: 'Flutter Demo',        theme: ThemeData(          primarySwatch: Colors.blue,        ),        initialRoute: '/',        routes: {          '/': (context) => const Login(),          '/home':(context) => const Home(),          '/profile': (context) => const Profile()        },        // home: const MyHomePage(title: 'Flutter Demo Home Page'),      ),    );  }}

Screens

Kita akan melanjutkan proses pembuatan screen di contoh aplikasi ini:

Login

Sebagai Contoh Pertama,

  • kita akan coba buat form atau field untuk inputan nama.
  • Disini kita coba memecah inputan menjadi widget kecil baru (Tidak berada 1 tempat di Widget Build() dan hanya memanggil nya saja).
lib/screens/login.dart
import 'package:belajar_form/providers/auth.dart';import 'package:flutter/material.dart';import 'package:provider/provider.dart';class Login extends StatefulWidget {  const Login({Key? key}) : super(key: key);    State<Login> createState() => _LoginState();}class _LoginState extends State<Login> {    // Define Variable  final _formUserKey = GlobalKey<FormState>();  final TextEditingController _nameField = TextEditingController();  // Akan ada variable lain nanti disini ...  // Define Small Widget  Widget inputName() {    return Container(      margin: const EdgeInsets.only(bottom: 20, top: 5),      child: TextFormField(        controller: _nameField,        decoration: InputDecoration(          hintText: "Steve Rogers",          labelText: "Nama Lengkap",          icon: const Icon(Icons.people),          border:              OutlineInputBorder(borderRadius: BorderRadius.circular(5)),        ),        validator: (value) {          if (value == null || value.isEmpty) {            return 'Nama Tidak Boleh Kosong !';          }          return null;        },      ),    );  }  // Akan Ada Widget Lagi Nanti Disini ...    Widget build(BuildContext context) {    return Scaffold(      appBar: AppBar(        title: const Text('Login'),      ),      resizeToAvoidBottomInset: false,      body: Center(        child: Padding(          padding: const EdgeInsets.all(15),          child:  SingleChildScrollView(            child: Form(              key: _formUserKey,              autovalidateMode: AutovalidateMode.onUserInteraction,              child: Column(                mainAxisAlignment: MainAxisAlignment.center,                children: <Widget>[                  inputName(), // Di Buat Setelah Widget Kecil untuk Inputan Nama nya telah dibuat sebelumnya                  // Akan kita panggil widget lain nya..                ],              ),            ),          )        ),      )    );  }}

Setelah itu kita dapat lanjutkan hal yang sama untuk inputan lainnya:

lib/screens/login.dart
import 'package:belajar_form/providers/auth.dart';import 'package:flutter/material.dart';import 'package:provider/provider.dart';class Login extends StatefulWidget {  const Login({Key? key}) : super(key: key);    State<Login> createState() => _LoginState();}class _LoginState extends State<Login> {  // Define Variable  final _formUserKey = GlobalKey<FormState>();  bool _isMarried = false;  String? _genderData;  final TextEditingController _nameField = TextEditingController();  final TextEditingController _emailField = TextEditingController();  final Map<String, bool> _checklistData = {    "PHP": false,    "ReactJS": false,    "Go": false,  };  final List _skills = [];  Map<String, dynamic> formData = {    "name": null,    "email": null,    "isMarried": null,    "gender": null,    "skills": null  };  // Define Small Widget  Widget inputName() {    return Container(      margin: const EdgeInsets.only(bottom: 20, top: 5),      child: TextFormField(        controller: _nameField,        decoration: InputDecoration(          hintText: "Steve Rogers",          labelText: "Nama Lengkap",          icon: const Icon(Icons.people),          border:              OutlineInputBorder(borderRadius: BorderRadius.circular(5)),        ),        validator: (value) {          if (value == null || value.isEmpty) {            return 'Nama Tidak Boleh Kosong !';          }          return null;        },      ),    );  }  Widget inputEmail() {    return Container(      margin: const EdgeInsets.only(bottom: 20),      child: TextFormField(        controller: _emailField,        decoration: InputDecoration(          hintText: "email@domain.com",          labelText: "e-Mail",          icon: const Icon(Icons.email),          border:              OutlineInputBorder(borderRadius: BorderRadius.circular(5)),        ),        validator: (value) {          if (value == null || value.isEmpty) {            return 'Email Tidak Boleh Kosong !';          }          return null;        },      ),    );  }  Widget inputIsMarried() {    return Container(      margin: const EdgeInsets.only(bottom: 20),      child: Row(        mainAxisAlignment: MainAxisAlignment.spaceBetween,        children: [          Text('${_isMarried ? "Menikah" : "Belum Menikah"}'),          Switch(            value: _isMarried,             onChanged: (value) {              setState(() {                _isMarried = value;              });            }          )        ],      )    );  }   Widget inputGender() {    return Container(      margin: const EdgeInsets.only(bottom: 20),      child: Column(        children: [          const Text('Jenis Kelamin'),          ListTile(            title: const Text('Laki-Laki'),            leading: Radio(                value: "Laki-Laki",                groupValue: _genderData,                onChanged: (value) {                  setState(() {                    _genderData = value.toString();                  });                }),          ),          ListTile(            title: const Text('Perempuan'),            leading: Radio(              value: "Perempuan",              groupValue: _genderData,              onChanged: (value) {                setState(() {                  _genderData = value.toString();                });              }),          ),        ],      ),    );  }  Widget inputSkills() {    return Container(      margin: const EdgeInsets.only(bottom: 20),      child: Column(        children: [          const Text('SKILLS'),          Row(            mainAxisAlignment: MainAxisAlignment.spaceBetween,            children: [              const Text('PHP'),              Checkbox(                value: _checklistData['PHP'],                 onChanged: (value) {                  if (value == true && !_skills.contains('PHP')) {                    _skills.add('PHP');                  } else if (value == false && _skills.contains('PHP')) {                    _skills.remove('PHP');                  }                  setState(() {                    _checklistData['PHP'] = value!;                  });                }              )            ],          ),          Row(            mainAxisAlignment: MainAxisAlignment.spaceBetween,            children: [              const Text('ReactJS'),              Checkbox(                value: _checklistData['ReactJS'],                onChanged: (value) {                  if (value == true && !_skills.contains('ReactJS')) {                    _skills.add('ReactJS');                  } else if (value == false && _skills.contains('ReactJS')) {                    _skills.remove('ReactJS');                  }                  setState(() {                    _checklistData['ReactJS'] = value!;                  });                })            ],          ),          Row(            mainAxisAlignment: MainAxisAlignment.spaceBetween,            children: [              const Text('Go'),              Checkbox(                value: _checklistData["Go"],                onChanged: (value) {                  if (value == true && !_skills.contains('Go')) {                    _skills.add('Go');                  } else if (value == false && _skills.contains('Go')) {                    _skills.remove('Go');                  }                  setState(() {                    _checklistData['Go'] = value!;                  });                })            ],          ),        ],      ),    );  }  Widget btnSubmit() {    AuthProvider authProvider = Provider.of<AuthProvider>(context);     return Container(      margin: const EdgeInsets.only(bottom: 20),      child: ElevatedButton(        child: const Text('Submit'),        onPressed: () {          if (_formUserKey.currentState!.validate()) {            ScaffoldMessenger.of(context).showSnackBar(              const SnackBar(content: Text('Processing Data')),            );            formData['name'] = _nameField.text;            formData['email'] = _emailField.text;            formData['isMarried'] = _isMarried;            formData['gender'] = _genderData;            formData['skills'] = _skills;            authProvider.simulateLogin(formData);            Navigator.pushNamed(              context,              '/home'            );                                 } else {            ScaffoldMessenger.of(context).showSnackBar(                const SnackBar(content: Text('Validation Fail !')),              );          }        },      )    );  }    Widget build(BuildContext context) {    return Scaffold(      appBar: AppBar(        title: const Text('Login'),      ),      resizeToAvoidBottomInset: false,      body: Center(        child: Padding(          padding: const EdgeInsets.all(15),          child:  SingleChildScrollView(            child: Form(              key: _formUserKey,              autovalidateMode: AutovalidateMode.onUserInteraction,              child: Column(                mainAxisAlignment: MainAxisAlignment.center,                children: <Widget>[                  inputName(),                  inputEmail(),                  inputIsMarried(),                  inputGender(),                  inputSkills(),                  btnSubmit()                ],              ),            ),          )        ),      )    );  } }

Home

Disini kita akan menampilkan data name dari Provider

lib/screens/home.dart
import 'package:belajar_form/providers/auth.dart';import 'package:flutter/material.dart';import 'package:provider/provider.dart';class Home extends StatelessWidget {  const Home({Key? key}) : super(key: key);    Widget build(BuildContext context) {    AuthProvider authProvider = Provider.of<AuthProvider>(context);    return Scaffold(      appBar: AppBar(        title: const Text('Home'),      ),      body: Center(        child: Column(          mainAxisAlignment: MainAxisAlignment.center,          children: [            const Text('Welcome !'),            Text(              '${authProvider.user.name.toString()}',               style: const TextStyle(                fontSize: 20,                fontWeight: FontWeight.bold                )            ),            ElevatedButton(              onPressed: () {                Navigator.pushNamed(                  context,                   '/profile'                );              },               child: const Text('See My Profile'),            )          ],        ),      ),    );  }}

Profile

Disini kita akan menampilkan semua data dari Provider Auth

lib/screens/profile.dart
import 'package:belajar_form/providers/auth.dart';import 'package:flutter/material.dart';import 'package:provider/provider.dart';class Profile extends StatelessWidget {  const Profile({Key? key}) : super(key: key);    Widget build(BuildContext context) {    AuthProvider authProvider = Provider.of<AuthProvider>(context);        return Scaffold(      appBar: AppBar(        title: const Text('Profile'),      ),      body: Center(        child: Padding(          padding: const EdgeInsets.all(14),          child: Column(            mainAxisAlignment: MainAxisAlignment.center,            children: <Widget>[              const Text('Halaman Profile Nih !'),              Row(                mainAxisAlignment: MainAxisAlignment.spaceBetween,                children: [                  const Text(                    'Nama: ',                    style:                      TextStyle(                        fontSize: 20,                         fontWeight: FontWeight.bold                      )                  ),                  Text(                    '${authProvider.user.name}',                    style: const TextStyle(                      fontSize: 20,                      fontWeight: FontWeight.bold                    ),                  )                ],              ),              Row(                mainAxisAlignment: MainAxisAlignment.spaceBetween,                children: [                  const Text(                    'e-Mail: ',                    style:                      TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),                  Text(                    '${authProvider.user.email}',                    style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),                  )                ],              ),              Row(                mainAxisAlignment: MainAxisAlignment.spaceBetween,                children: [                  const Text('Skills: ',                    style:                      TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),                  Text(                    '${authProvider.user.skills.toString()}',                    style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),                  )                ],              ),              Row(                mainAxisAlignment: MainAxisAlignment.spaceBetween,                children: [                  const Text('Sudah Menikah: ',                    style:                        TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),                  Text(                    '${authProvider.user.isMarried}',                    style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),                  )                ],              ),              Row(                mainAxisAlignment: MainAxisAlignment.spaceBetween,                children: [                  const Text('Gender: ',                    style:                      TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),                  Text(                    '${authProvider.user.gender}',                    style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),                  )                ],              )            ],          ),        )      ),    );  }}

Hasil

Berikut Demo dari yang kita Buat