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:
- Package Provider
- Pengetahuan Widget Dasar
Struktur Folder
Kita akan membuat struktur folder dan file seperti berikut:

Silahkan Buat Terlebih dahulu !
Layar Awal
- 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
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 ), ) ), ) ); }}Menggunakan Stateless Widget (Karna Hanya akan mengambil data dari Auth Provider)
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'), ) ], ), ), ); }}Menggunakan Stateless Widget (Karna Hanya akan mengambil data dari Auth Provider)
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
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
Dalam materi kali ini hanya akan simulasi saja terkait autentikasinya
- 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
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.
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).
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:
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
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
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