Mengenal Widget Flutter #11: CRUD Data Pegawai Part 3

Mengenal Widget Flutter #11: CRUD Data Pegawai Part 3

Pendahuluan

Jika pada seri sebelumnya kita sudah belajar bagaimana menambahkan sebuah data baru ke dalam database melalui API yang telah disediakan, maka pada seri kali ini ada beberapa bagian yang diangkat sebagai pokok bahasan, diantaranya adalah bagaimana cara memperbaharui atau meng-update data pegawai dan yang terakhir adalah fitur untuk menghapus data pegawai.

Skenario yang diinginkan adalah untuk fitur edit data, user bisa melakukan tap pada list data pegawai dan secara otomatis akan diarahkan ke halaman edit dengan menampilkan data pegawai yang di-tap. Adapun schema untuk menghapus data akan bekerja ketika user menggeser salah satu item dari list pegawai ke kiri atau lebih dikenal dengan dismissable.

Update Data Pegawai

Langkah pertama dalam menyelesaikan fitur ini adalah dengan membuat sebuah file baru yang akan meng-handle form edit data, buat file bernama employee_edit.dart di dalam folder lib/pages dan masukkan code berikut

import 'package:dw_employee_crud/pages/employee.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../providers/employee_provider.dart';

class EmployeeEdit extends StatefulWidget {
  final String id; //INISIASI VARIABLE ID;
  EmployeeEdit({this.id}); //BUAT CONSTRUCT UNTUK MEMINTA DATA ID

  @override
  _EmployeeEditState createState() => _EmployeeEditState();
}

class _EmployeeEditState extends State<EmployeeEdit> {
  final TextEditingController _name = TextEditingController();
  final TextEditingController _salary = TextEditingController();
  final TextEditingController _age = TextEditingController();
  bool _isLoading = false;

  final snackbarKey = GlobalKey<ScaffoldState>();

  FocusNode salaryNode = FocusNode();
  FocusNode ageNode = FocusNode();

  //KETIKA CLASS INI AKAN DI-RENDER, MAKA AKAN MENJALANKAN FUNGSI BERIKUT
  @override
  void initState() {
    //BUAT DELAY
    Future.delayed(Duration.zero, () {
      //MENJALANKAN FUNGSI FINDEMPLOYEE UNTUK MENCARI DATA EMPLOYEE BERDASARKAN IDNYA
      //CARA MENGAKSES ID DARI CONSTRUCTOR PADA STATEFUL WIDGET ADALAH 
     //WIDGET DOT DAN DIIKUTI DENGAN VARIABLE YANG INGIN DIAKSES
      Provider.of<EmployeeProvider>(context, listen: false).findEmployee(widget.id).then((response) {
        //JIKA DITEMUKAN, MAKA DATA TERUS KITA MASUKKAN KE DALAM VARIABLE CONTROLLER UNTUK TEKS FIELD
        _name.text = response.employeeName;
        _salary.text = response.employeeSalary;
        _age.text = response.employeeAge;
      });
    });
    super.initState();
  }

  void submit(BuildContext context) {
    if (!_isLoading) {
      setState(() {
        _isLoading = true;
      });
      //ADAPUN UNTUK PROSES UPDATE, JALANKAN FUNGSI UPDATEEMPLOYEE() DENGNA MENGIRIMKAN DATA YANG SAMA KETIKA ADD DATA, HANYA SAJA DITAMBAHKAN DENGAN ID PEGAWAI
      Provider.of<EmployeeProvider>(context, listen: false)
          .updateEmployee(widget.id, _name.text, _salary.text, _age.text)
          .then((res) {
        if (res) {
          Navigator.of(context).pushReplacement(
              MaterialPageRoute(builder: (context) => Employee()));
        } else {
          var snackbar = SnackBar(content: Text('Ops, Error. Hubungi Admin'),);
          snackbarKey.currentState.showSnackBar(snackbar);
          setState(() {
            _isLoading = false;
          });
        }
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: snackbarKey,
      appBar: AppBar(
        title: Text('Edit Employee'),
        actions: <Widget>[
          FlatButton(
            child: _isLoading
                ? CircularProgressIndicator(
                    valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
                  )
                : Icon(
                    Icons.save,
                    color: Colors.white,
                  ),
            onPressed: () => submit(context),
          )
        ],
      ),
      body: Container(
        margin: EdgeInsets.all(10),
        child: ListView(
          children: <Widget>[
            TextField(
              controller: _name,
              decoration: InputDecoration(
                focusedBorder: UnderlineInputBorder(
                  borderSide: BorderSide(
                    color: Colors.pinkAccent,
                  ),
                ),
                hintText: 'Nama Lengkap',
              ),
              onSubmitted: (_) {
                FocusScope.of(context).requestFocus(salaryNode);
              },
            ),
            TextField(
              controller: _salary,
              focusNode: salaryNode,
              decoration: InputDecoration(
                focusedBorder: UnderlineInputBorder(
                  borderSide: BorderSide(
                    color: Colors.pinkAccent,
                  ),
                ),
                hintText: 'Gaji',
              ),
              onSubmitted: (_) {
                FocusScope.of(context).requestFocus(ageNode);
              },
            ),
            TextField(
              controller: _age,
              focusNode: ageNode,
              decoration: InputDecoration(
                focusedBorder: UnderlineInputBorder(
                  borderSide: BorderSide(
                    color: Colors.pinkAccent,
                  ),
                ),
                hintText: 'Umur',
              ),
            ),
          ],
        ),
      ),
    );
  }
}

Note: Adapun penjelasan lainnya sama saja dengan penjelasan pada artikel sebelumnya. Codingan yang berbeda dari employee_add.dart hanya pada bagian yang saya berikan komentar.

Kemudian buka file lib/pages/employee.dart dan wrap widget Card() yang ada di dalam ListView.build() menjadi

return ListView.builder(
  itemCount: data.dataEmployee.length,
  itemBuilder: (context, i) {
    //WRAP DENGAN INKWELL UNTUK MENGGUNAKAN ATTRIBUTE ONTAPNYA
    return InkWell(
      onTap: () {
        //DIMANA KETIKA DI-TAP MAKA AKAN DIARAHKAN
        Navigator.of(context).push(
          //KE CLASS EMPLOYEEEDIT DENGAN MENGIRIMKAN ID EMPLOYEE
          MaterialPageRoute(
            builder: (context) => EmployeeEdit(id: data.dataEmployee[i].id,),
          ),
        );
      },
      child: Card(
        elevation: 8,
        child: ListTile(
          title: Text(
            data.dataEmployee[i].employeeName,
            style: TextStyle(
                fontSize: 18, fontWeight: FontWeight.bold),
          ),
          subtitle: Text(
              'Umur: ${data.dataEmployee[i].employeeAge}'),
          trailing: Text(
              "\$${data.dataEmployee[i].employeeSalary}"),
        ),
      ),
    );
  },
);

Jangan lupa pada bagian import statement, tambahkan code

import './employee_edit.dart';

Adapun fungsi untuk meng-handle pencarian data pegawai adalah dengan menambahkan code di bawah ini ke dalam file lib/providers/employee_provider.dart

Future<EmployeeModel> findEmployee(String id) async {
  return _data.firstWhere((i) => i.id == id); //JADI KITA CARI DATA BERDASARKAN ID DAN DATA PERTAMA AKAN DISELECT
}

Masih dengan file yang sama, dimana fungsi untuk melakukan update data adalah dengan menambahkan code.

//JADI KITA MINTA DATA YANG AKAN DIUPDATE
Future<bool> updateEmployee(id, name, salary, age) async {
  final url = 'http://employee-crud-flutter.daengweb.id/update.php';
  //DAN MELAKUKAN REQUEST UNTUK UPDATE DATA PADA URL DIATAS
  //DENGAN MENGIRIMKAN DATA YANG AKAN DI-UPDATE
  final response = await http.post(url, body: {
    'id': id,
    'employee_name': name,
    'employee_salary': salary,
    'employee_age': age
  });

  final result = json.decode(response.body); //DECODE RESPONSE-NYA
  //LAKUKAN PENGECEKAN, JIKA STATUSNYA 200 DAN BERHASIL
  if (response.statusCode == 200 && result['status'] == 'success') {
    notifyListeners(); //MAKA INFORMASIKAN KE WIDGET BAHWA TERJADI PERUBAHAN PADA STATE
    return true;
  }
  return false;
}

mengenal widget flutter - edit employee

[ISSUE] Remove Back Arrow Button

Terdapat sebuah kendala dimana ketika melakukan redirect dari form edit maupun form add ke halaman depan yang menampilkan data pegawai, dimana tombol arrow back masih tetap ditampilkan meskipun kita sudah menggunakan pushReplacement(). Untuk mengatasinya, modifikasi code Navigator baik pada halaman edit maupun add dengan menggunakan method pushAndRemoveUntil().

Navigator.of(context).pushAndRemoveUntil(
  MaterialPageRoute(builder: (context) => Employee()), (route) => false);

Hapus Data Pegawai

Ada dua tahapan dalam menyelesaikan fungsi hapus data, dimana tahapan pertama adalah membuat dismissible dengan dialog confirmation dan yang kedua ada fungsi untuk melakukan request ke API. Buka file lib/pages/employee.dart dan wrap Card() yang ada di dalam ListView.builder() dengan widget Dismissible.

//[.. CODE LAINNYA ..]

child: Dismissible(
  key: UniqueKey(), //GENERATE UNIQUE KEY UTK MASING-MASING ITEM
  direction: DismissDirection.endToStart, //ATUR ARAH DISMISSNYA
  //BUAT KONFIRMASI KETIKA USER INGIN MENGHAPUS DATA
  confirmDismiss: (DismissDirection direction) async {
    //TAMPILKAN DIALOG KONFIRMASI
    final bool res = await showDialog(context: context, builder: (BuildContext context) {
      //DENGAN MENGGUNAKAN ALERT DIALOG
      return AlertDialog(
        title: Text('Konfirmasi'),
        content: Text('Kamu Yakin?'),
        actions: <Widget>[
          //KITA SET DUA BUAH TOMBOL UNTUK HAPUS DAN CANCEL DENGAN VALUE BOOLEAN
          FlatButton(onPressed: () => Navigator.of(context).pop(true), child: Text('HAPUS'),),
          FlatButton(onPressed: () => Navigator.of(context).pop(false), child: Text('BATALKAN'),)
        ],
      );
    });
    return res;
  },
  onDismissed: (value) {
    //KETIKA VALUENYA TRUE, MAKA FUNGSI INI AKAN DIJALANKAN, UNTUK MENGHAPUS DATA
    Provider.of<EmployeeProvider>(context, listen: false).deleteEmployee(data.dataEmployee[i].id);
  },
  child: Card(
    elevation: 8,
    child: ListTile(
      title: Text(
        data.dataEmployee[i].employeeName,
        style: TextStyle(
            fontSize: 18, fontWeight: FontWeight.bold),
      ),
      subtitle: Text(
          'Umur: ${data.dataEmployee[i].employeeAge}'),
      trailing: Text(
          "\$${data.dataEmployee[i].employeeSalary}"),
    ),
  ),
),
  
//[.. CODE LAINNYA ..]

Tugas terakhir adalah membuat sebuah fungsi untuk melakukan request server berdasarkan API yang sudah ditentukan. Buka file employee_provider.dart dan tambahkan method berikut

Future<void> deleteEmployee(String id) async {
  final url = 'http://employee-crud-flutter.daengweb.id/delete.php';
  await http.get(url + '?id=$id');
}

mengenal widget flutter - edit employee

Kesimpulan

Menutup seri belajar CRUD di Flutter dimana kita sudah membahas secara keseluruhan yang meliputi Create Data, Read data, Update Data dan Delete Data. Sepanjang seri ini kita telah belajar banyak hal, diantaranya menampilkan form, membuat alert dialog, snackbar dialog, membuat indicator loading dan lain sebagainya.

Adapun dokumentasi code dari artikel ini bisa dilihat di Github.

Category:
Share:

Comments