Tutorial CRUD Codeigniter 4 dan Flutter #4 – Update Data. Kali ini saya akan melanjutkan pembahasan sebelumnya yaitu edit dan update data.
Sebelum melanjutkan, jika Anda belum membaca dan mempraktikan part ke 3 tentang detail data, silahkan kunjungi:
Rekomendasi: Tutorial CRUD Codeigniter 4 dan Flutter #3 – Detail Data
Bila sudah, sekarang kita akan melanjutkan langkah berikutnya. Yaitu membuat halaman edit dan proses update data di Flutter dan mengirimkan data (method POST) melalui REST API Codeigniter 4.
Silahkan ikuti beberapa langkah di bawah ini:
Step 1 – Tambahkan Function Update User di Model User
Silahkan buka file User_model.php
yang ada di dalam direktori app/Models
.
Kemudian ketik kode berikut ini:
public function updateUser($data, $id) { return $this->db->table($this->table)->update($data, ['id' => $id]); }
Penjelasan:
Pada bagian ini kita melakukan update data berdasarkan parameter id
sebagai primary key dari table users
.
Step 2 – Tambahkan Function Update di Controller
public function update($id = NULL) { $fullname = $this->request->getPost('fullname'); $grade = $this->request->getPost('grade'); $gender = $this->request->getPost('gender'); $phone = $this->request->getPost('phone'); $data = [ 'fullname' => $fullname, 'grade' => $grade, 'gender' => $gender, 'phone' => $phone ]; $simpan = $this->model->updateUser($data, $id); if($simpan){ $msg = ['message' => 'Updated user successfully']; $response = [ 'status' => 200, 'error' => false, 'data' => $msg, ]; return $this->respond($response, 200); } }
Penjelasan:
Biasanya proses edit menggunakan method PUT, tapi di sini saya menggunakan method POST.
Menurut saya ga masalah kalau kita menggunakan POST. Ini sejalan dengan dokumentasi Codeigniter 4 yang membolehkan menggunakan presenter.
Anda bisa membaca dokumentasi lengkap tentang Codeigniter 4 Rest API di sini.
Step 3 – Testing Update Data Melalui Postman
Silahkan gunakan URL ke 1 ini:
localhost:8080/user/update/id
… atau URL ke 2 ini:
localhost/belajar-codeigniter-4/ci4_restapi_flutter/public/index.php/user/update/id
Catatan:
Silahkan ubah kata id yang saya cetak tebal dengan id / primary key yang tersedia di table users pada komputer Anda.
Jika berjalan dengan lancar, hasilnya adalah:
Step 4 – Tambahkan Function Update User di User Service
Buka kembali file user_service.dart
pada direktori lib/service
.
Kemudian ketik kode berikut ini:
Future<bool> updateUser({int id, User data}) async { final response = await client.post( "$baseUrl/user/update/$id", body: { "fullname" : data.fullName, "grade" : data.grade, "gender" : data.gender, "phone" : data.phone } ); if (response.statusCode == 200) { return true; } else { return false; } }
Step 5 – Buat Halaman Edit Data
Kemudian buat file baru bernama user_edit.dart
dan simpan di dalam direktori lib/screen
.
lib/screen/user_edit.dart
import 'package:flutter/material.dart'; import 'package:flutter_crud_ci4/model/user.dart'; import 'package:flutter_crud_ci4/service/user_service.dart'; import 'package:flutter_crud_ci4/util/capitalize.dart'; import 'package:flutter_crud_ci4/widget/form_label.dart'; import 'package:flutter_crud_ci4/widget/radio_button.dart'; class FormEditUser extends StatefulWidget { final User user; final int id; FormEditUser({@required this.user, @required this.id, Key key}):super(key: key); @override _FormEditUserState createState() => _FormEditUserState(); } class _FormEditUserState extends State<FormEditUser> { UserApiService apiService; static const genders = User.genders; // from domain static const grades = User.grades; // from domain // upayakan menggunakan global key final _formKey = GlobalKey<FormState>(); final GlobalKey<ScaffoldState> _scaffoldkey = GlobalKey<ScaffoldState>(); bool _autovalidate = false; // jarak antar form double _gap = 16.0; // focus node FocusNode _fullnameFocus, _phoneFocus; // variabel value null String _fullname, _gender, _grade, _phone; TextEditingController _fullnameController, _phoneController; final List<DropdownMenuItem<String>> _gradeItems = grades .map((String val) => DropdownMenuItem<String>( value: val, child: Text(val.toUpperCase()), )) .toList(); @override void initState() { super.initState(); _gender = 'pria'; _fullnameFocus = FocusNode(); _phoneFocus = FocusNode(); _fullnameController = TextEditingController(); _phoneController = TextEditingController(); if(widget.user != null && widget.id != null){ _fullname = widget.user.fullName; _phone = widget.user.phone; _gender = widget.user.gender; _grade = widget.user.grade; _fullnameController.value = TextEditingValue( text: widget.user.fullName, selection: TextSelection.collapsed(offset: widget.user.fullName.length) ); _phoneController.value = TextEditingValue( text: widget.user.phone, selection: TextSelection.collapsed(offset: widget.user.phone.length) ); } apiService = UserApiService(); } @override void dispose() { // Clean up the focus node when the Form is disposed. _fullnameFocus.dispose(); _phoneFocus.dispose(); _fullnameController.dispose(); _phoneController.dispose(); _formKey.currentState?.dispose(); super.dispose(); } _showSnackBar(message){ final snackbar = SnackBar(content: Text(message),); _scaffoldkey.currentState.showSnackBar(snackbar); } @override Widget build(BuildContext context) { return Scaffold( key: _scaffoldkey, appBar: AppBar( leading: IconButton( icon: Icon(Icons.arrow_back), onPressed: () => { Navigator.pop(context), }, ), title: Text("Edit User"), ), body: SingleChildScrollView( child: ConstrainedBox( constraints: BoxConstraints(), child: Form( // key form as csrf key: _formKey, autovalidate: _autovalidate, child: Padding( padding: const EdgeInsets.all(8.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ TextFormField( controller: _fullnameController, focusNode: _fullnameFocus, textInputAction: TextInputAction.next, keyboardType: TextInputType.text, decoration: const InputDecoration( border: OutlineInputBorder(), labelText: 'Nama Lengkap', ), onSaved: (String value) { // will trigger when saved print('onsaved _fullname $value'); _fullname = value; }, onFieldSubmitted: (term) { _fullnameFocus.unfocus(); FocusScope.of(context).requestFocus(_phoneFocus); }, validator: (val) { if(val.isEmpty){ return "Nama lengkap wajib diisi"; } return null; }, ), SizedBox( height: _gap, ), TextFormField( controller: _phoneController, focusNode: _phoneFocus, textInputAction: TextInputAction.next, keyboardType: TextInputType.phone, decoration: const InputDecoration( border: OutlineInputBorder(), labelText: 'No. Hp', ), onSaved: (String value) { // will trigger when saved print('onsaved _hone $value'); _phone = value; }, onFieldSubmitted: (term) { _phoneFocus.unfocus(); FocusScope.of(context).requestFocus(_fullnameFocus); }, validator: (val) { if(val.isEmpty){ return "No hp wajib diisi"; } return null; }, ), SizedBox( height: _gap, ), FormLabel('Jenis Kelamin'), Row( children: genders .map((String val) => RadioButton<String>( value: val, groupValue: _gender, label: Text(capitalize(val)), onChanged: (String value) { setState(() => _gender = value); })) .toList(), ), SizedBox( height: _gap, ), FormLabel('Jenjang'), Padding( padding: const EdgeInsets.only(left: 5.0), child: DropdownButton( value: _grade, hint: Text('Pilih jenjang'), items: _gradeItems, isExpanded: true, onChanged: (String value) { setState(() { _grade = value; }); }, ), ), ], ), ), ), ), ), floatingActionButton: FloatingActionButton( child: Icon( Icons.save, color: Colors.white, ), onPressed: () { final form = _formKey.currentState; if (form.validate()) { // Process data. form.save(); // required to trigger onSaved props User _user = User(); if(_grade == null){ _showSnackBar("Jenjang tidak boleh kosong"); } else if(_gender == null){ _showSnackBar("Gender tidak boleh kosong"); } else { _user.fullName = _fullname; _user.grade = _grade; _user.gender = _gender; _user.phone = _phone; print(_user); // snackbar success dan error final onSuccess = (Object success) => Navigator.pop(context); final onError = (Object error) => _showSnackBar("Tidak bisa ubah data"); apiService.updateUser(id: widget.user.id, data: _user).then(onSuccess).catchError(onError); } } else { setState(() { _autovalidate = true; }); } } ), ); } }
Step 6 – Modifikasi File Detail di Flutter
Buka kembali file user_detail.dart
pada direktori lib/screen
.
Kemudian cari kode berikut ini:
... ... IconButton( icon: Icon(Icons.edit), onPressed: () {} ), ... ...
Ubah menjadi:
... ... IconButton( icon: Icon(Icons.edit), onPressed: () { Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => FormEditUser( user: _user, id: widget.id), ), ); } ), ... ...
Step 7 – Testing Proses Update Data
Now, kita akan menjalankan project menggunakan perintah:
flutter run
Jika berjalan dengan lancar, berikut hasilnya:
Apa Selanjutnya?
Alhamdulillah, tutorial crud codeigniter 4 dan flutter part ke 4 – update data sudah selesai.
… tapi jangan puas dulu ya. Sebab masih ada pembahasan soal delete data.
… dan saya berharap, semoga tidak ada error yang dialami oleh teman-teman semuanya.
Jika pun ada, Anda bisa bertanya di kolom komentar atau mau lihat-lihat dulu perubahan source code yang ada di Github (perhatikan commit part 4 nya ya).
Ini linknya: Commit Part 4 – Update Data
Semoga tutorial crud codeigniter 4 dan flutter part ke 4 – update data ini bermanfaat dan selamat belajar …
Gan kenapa yah setelah aksi pada screen edit, data pada screen detailnya tidak auto berubah dengan data yang baru. Tapi di database, datanya sudah berubah…. Mohon bimbingannya
Rencananya saya mau buat seri lanjutan yang bahas tentang itu
yg aksi hapusnya belum ya pak?
Ini sudah mas https://ilmucoding.com/crud-codeigniter-4-flutter-delete-data/