Praktikum 3: Input Widgets dan Basic Form

Membuat form dasar, menerima, dan mengelola input dari pengguna di Flutter

PRAKTIKUM 3

Input Widgets dan Basic Form

1.1 Tujuan

Tujuan praktikum ini yaitu mahasiswa mampu membuat basic form untuk menerima inputan dari keyboard dan mengelola inputan:

  • Membuat beberapa input widgets.
  • Membuat dan mengontrol inputan dari user.

1.2 Alat

  • Computer/laptop yang telah terinstall lingkungan flutter development.

1.3 Teori

TextField

Widget dasar untuk menerima input teks dari keyboard.

TextFormField

Versi lengkap dari TextField yang secara otomatis terintegrasi dengan logika validasi dan manajemen state dari sebuah Form.Fiturnya antara lain:

  • Memiliki properti validator untuk memeriksa input.
  • Menampilkan pesan error secara otomatis jika validasi gagal.
  • Berinteraksi dengan FormState untuk melakukan validasi kolektif.
GlobalKey<FormState>

GlobalKey merupakan objek unik yang digunakan untuk mengidentifikasi dan mengakses FormState.FormState adalah kelas yang mengelola status dari Form, seperti status validasi setiap field.Method validate() pada FormState digunakan untuk menjalankan validasi pada setiap TextFormField di dalam Form.

setState()

setState() adalah method yang memberitahu Flutter bahwa state internal dari sebuah StatefulWidget telah berubah, sehingga widget tersebut perlu di-render ulang (rebuild) untuk menampilkan perubahan.

Kata Kunci `const`

Kata kunci const pada widget digunakan untuk membuat widget menjadi konstanta pada saat kompilasi (compile-time).Penggunaan const dapat meningkatkan performa karena widget akan dibuat sekali dan disimpan di memori, sehingga dapat digunakan kembali tanpa perlu build ulang.

1.4 Langkah-langkah

Praktikum 1: Basic Form dengan TextField
1. Membuat Tampilan Awal

Buat file baru form_textfield.dart di dalam folder lib dan buat tampilan dasar form menggunakan kode berikut.

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Basic Form'),
        ),
        body: const MyForm(),
      ),
    );
  }
}

class MyForm extends StatefulWidget {
  const MyForm({super.key});

  @override
  State createState() => _MyFormState();
}

class _MyFormState extends State {
  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(20.0),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          const Text('Masukkan nama anda :'),
          const SizedBox(height: 10),
          const TextField(
            decoration: InputDecoration(
                labelText: 'Nama Lengkap',
                hintText: 'Misalnya masnoer',
                border: OutlineInputBorder(),
                prefixIcon: Icon(Icons.person)),
          ),
          const SizedBox(height: 20),
          ElevatedButton(
            onPressed: () {},
            style: ElevatedButton.styleFrom(
                backgroundColor: Colors.amber, foregroundColor: Colors.black),
            child: const Text('Tampilkan nama'),
          )
        ],
      ),
    );
  }
}
2. Menambahkan TextEditingController

Pada class _MyFormState, tambahkan controller untuk mengambil dan membersihkan inputan.Controller berfungsi untuk mengambil inputan dari user.Method `dispose()` digunakan untuk membersihkan teks inputan.

final TextEditingController _textEditingController = TextEditingController();

@override
void dispose() {
  _textEditingController.dispose();
  super.dispose();
}
3. Menghubungkan Controller ke TextField

Tambahkan property controller pada widget TextField untuk menghubungkannya dengan controller yang telah dibuat.

TextField(
  controller: _textEditingController,
  // ... properti lainnya
),
4. Menambahkan Aksi pada Tombol

Ubah method onPressed pada ElevatedButton untuk mengambil teks dari controller dan menampilkannya dalam sebuah SnackBar.

onPressed: () {
  String inputText = _textEditingController.text;
  ScaffoldMessenger.of(context).showSnackBar(
    SnackBar(content: Text('Nama anda adalah, $inputText')),
  );
},

Praktikum 2: Basic Form dengan TextFormField
1. Membuat Tampilan Awal

Buat file baru form_textformfield.dart dan buat tampilan awal dengan dua TextFormField dan satu tombol.

2. Menambahkan State Management

Pada class state (misal: _MyFormTextState), tambahkan GlobalKey untuk form, controller untuk setiap field, dan method untuk submit.

final _formKey = GlobalKey();final _nameController = TextEditingController();final _emailController = TextEditingController();@override
void dispose() {_nameController.dispose();_emailController.dispose();super.dispose();}

void _submitForm() {if (_formKey.currentState!.validate()) {String name = _nameController.text;String email = _emailController.text;ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Validasi $name, $email Berhasil')),);
  }
}
3. Menambahkan Form Key dan Validator

Bungkus Column dengan widget Form dan berikan _formKey.Kemudian, tambahkan properti validator pada setiap TextFormField.

TextFormField untuk Nama:
TextFormField(
  controller: _nameController,decoration: const InputDecoration(
      labelText: "Nama", border: OutlineInputBorder()),validator: (value) {if (value == null || value.isEmpty) {return 'Masukkan nama anda';}
    return null;},
),
TextFormField untuk Email:
TextFormField(
  controller: _emailController,decoration: const InputDecoration(
      labelText: "Email", border: OutlineInputBorder()),validator: (value) {if (value == null || value.isEmpty) {return 'Masukkan email anda';}
    if (!value.contains('@')) {return 'Email tidak valid';}
    return null;},
),
4. Menghubungkan Aksi Tombol

Panggil method _submitForm dari onPressed pada ElevatedButton.

ElevatedButton(
  onPressed: _submitForm, child: const Text('Submit')
)
5. Kode Program Lengkap
import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text("Basic Form TextFormField"),
        ),
        body: const MyFormText(),
      ),
    );
  }
}

class MyFormText extends StatefulWidget {
  const MyFormText({super.key});

  @override
  State createState() => _MyFormTextState();
}

class _MyFormTextState extends State {
  final _formKey = GlobalKey();
  final _nameController = TextEditingController();
  final _emailController = TextEditingController();

  @override
  void dispose() {
    _nameController.dispose();
    _emailController.dispose();
    super.dispose();
  }

  void _submitForm() {
    if (_formKey.currentState!.validate()) {
      String name = _nameController.text;
      String email = _emailController.text;
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Validasi $name, $email Berhasil')),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Form(
      key: _formKey,
      child: Padding(
        padding: const EdgeInsets.all(20.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            TextFormField(
              controller: _nameController,
              decoration: const InputDecoration(
                  labelText: "Nama", border: OutlineInputBorder()),
              validator: (value) {
                if (value == null || value.isEmpty) {
                  return 'Masukkan nama anda';
                }
                return null;
              },
            ),
            const SizedBox(height: 10),
            TextFormField(
              controller: _emailController,
              decoration: const InputDecoration(
                  labelText: "Email", border: OutlineInputBorder()),
              validator: (value) {
                if (value == null || value.isEmpty) {
                  return 'Masukkan email anda';
                }
                if (!value.contains('@')) {
                  return 'Email tidak valid';
                }
                return null;
              },
            ),
            const SizedBox(height: 20),
            SizedBox(
              width: double.infinity,
              child: ElevatedButton(
                onPressed: _submitForm,
                child: const Text('Submit'),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

1.5 Latihan/Tugas

Pengerjaan Tugas Modul 3: Form Pendaftaran (Kelas B)

Sesuai dengan instruksi, dibuat sebuah form pendaftaran pengguna yang terdiri dari field nama, email, password, dan konfirmasi password.Aplikasi ini menggunakan `StatefulWidget` untuk mengelola input dan validasi pada setiap `TextFormField`.Validasi memastikan email mengandung format '@' dan password cocok dengan konfirmasi password.

Langkah Pengerjaan
  1. File `main.dart`: File ini berfungsi sebagai titik masuk aplikasi dan mengatur `MaterialApp` untuk memanggil halaman form pendaftaran.
  2. File `user_registration_form.dart`: File ini berisi `StatefulWidget` utama.
    • Menggunakan `GlobalKey` untuk mengelola dan memvalidasi form.
    • Menggunakan `TextEditingController` untuk setiap input field, yang penting untuk membandingkan nilai password dan konfirmasi password.
    • Menerapkan fungsi `validator` pada setiap `TextFormField` sesuai dengan persyaratan.
    • Membuat method `_submitForm` yang akan dipanggil oleh tombol "Submit" untuk memicu validasi.
Kode Program Lengkap
File: `main.dart`
import 'package:flutter/material.dart';
import 'user_registration_form.dart'; // Impor file form

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Form Pendaftaran',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      // Atur home ke widget form pendaftaran
      home: const UserRegistrationForm(),
    );
  }
}
File: `user_registration_form.dart`
import 'package:flutter/material.dart';

// Gunakan StatefulWidget sesuai instruksi
class UserRegistrationForm extends StatefulWidget {
  const UserRegistrationForm({super.key});

  @override
  State createState() => _UserRegistrationFormState();
}

class _UserRegistrationFormState extends State {
  // GlobalKey untuk mengelola state Form
  final _formKey = GlobalKey();

  // Controller untuk setiap TextFormField
  final _nameController = TextEditingController();
  final _emailController = TextEditingController();
  final _passwordController = TextEditingController();
  final _confirmPasswordController = TextEditingController();

  @override
  void dispose() {
    // Bersihkan controller saat widget tidak lagi digunakan
    _nameController.dispose();
    _emailController.dispose();
    _passwordController.dispose();
    _confirmPasswordController.dispose();
    super.dispose();
  }

  // Method yang dipanggil saat tombol ditekan
  void _submitForm() {
    // `validate()` akan memicu semua fungsi validator di dalam Form
    if (_formKey.currentState!.validate()) {
      // Jika semua validasi berhasil, tampilkan SnackBar
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('Pendaftaran Berhasil!')),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Form Pendaftaran Pengguna'),
      ),
      body: Form(
        key: _formKey, // Hubungkan GlobalKey dengan Form
        child: SingleChildScrollView( // Agar bisa di-scroll jika layar kecil
          padding: const EdgeInsets.all(20.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              // TextFormField untuk Nama
              TextFormField(
                controller: _nameController,
                decoration: const InputDecoration(
                  labelText: 'Nama Lengkap',
                  border: OutlineInputBorder(),
                ),
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Nama tidak boleh kosong';
                  }
                  return null;
                },
              ),
              const SizedBox(height: 16.0),

              // TextFormField untuk Email
              TextFormField(
                controller: _emailController,
                decoration: const InputDecoration(
                  labelText: 'Email',
                  border: OutlineInputBorder(),
                ),
                keyboardType: TextInputType.emailAddress,
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Email tidak boleh kosong';
                  }
                  // Validasi email harus mengandung format '@'
                  if (!value.contains('@')) {
                    return 'Format email tidak valid';
                  }
                  return null;
                },
              ),
              const SizedBox(height: 16.0),

              // TextFormField untuk Password
              TextFormField(
                controller: _passwordController,
                obscureText: true, // Sembunyikan teks password
                decoration: const InputDecoration(
                  labelText: 'Password',
                  border: OutlineInputBorder(),
                ),
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Password tidak boleh kosong';
                  }
                  if (value.length < 6) {
                    return 'Password minimal 6 karakter';
                  }
                  return null;
                },
              ),
              const SizedBox(height: 16.0),

              // TextFormField untuk Konfirmasi Password
              TextFormField(
                controller: _confirmPasswordController,
                obscureText: true,
                decoration: const InputDecoration(
                  labelText: 'Konfirmasi Password',
                  border: OutlineInputBorder(),
                ),
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Konfirmasi password tidak boleh kosong';
                  }
                  // Validasi password dan confirm password harus sama
                  if (value != _passwordController.text) {
                    return 'Password tidak cocok';
                  }
                  return null;
                },
              ),
              const SizedBox(height: 24.0),

              // Tombol Submit
              ElevatedButton(
                // Panggil _submitForm saat tombol ditekan
                onPressed: _submitForm,
                style: ElevatedButton.styleFrom(
                  padding: const EdgeInsets.symmetric(vertical: 16.0),
                ),
                child: const Text('Submit'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Kembali ke Daftar Laporan