Home Mobile Belajar membuat sebuah CRUD pada Flutter menggunakan Provider State Management

Belajar membuat sebuah CRUD pada Flutter menggunakan Provider State Management

0

Pada kali ini kita akan mempelajari sebuah CRUD dengan menggunakan sebuah package yaitu provider. Berikut ini langkah-langkah dan cara untuk membuat sebuah CRUD dengan menggunakan Provider State Management:

  • Buatlah sebuah project baru pada flutter
  • Searching Pub.dev https://pub.dev/ dan ambil package Provider dan Http
  • Selanjutnya letakan pada file pubspec.yaml
dropdown_button2: ^2.0.0
http: ^0.13.5
provider: ^6.0.5
  • Selanjutnya buatlah sebuah backend untuk CRUD
  • Full Source Code

File Home Page

import 'package:flutter/material.dart';
import 'package:flutter5/form/form_page.dart';
import 'package:flutter5/home/home_provider.dart';
import 'package:provider/provider.dart';

class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);

@override
State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {

@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => HomeProvider(),
child: Consumer<HomeProvider>(
builder: (context, homeProvider, child) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: Text("Provider State Management"),
),
body: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Padding(
padding: const EdgeInsets.all(10),
child: homeProvider.isLoading == true
? Center(child: CircularProgressIndicator())
: homeProvider.listMahasiswa!.isEmpty
? Center(child: Text("No Data"))
: ListView.builder(
itemCount: homeProvider.listMahasiswa?.length ?? 0,
itemBuilder: (context, index) {
return Card(
shape: OutlineInputBorder(
borderRadius: BorderRadius.circular(20),
borderSide: BorderSide(color: Colors.blue)
),
child: Padding(
padding: const EdgeInsets.all(10),
child: ListTile(
onTap: () async{
await Navigator.push(context,
MaterialPageRoute(builder: (context) => FormPage(
isUpdate: true,
data: homeProvider.listMahasiswa?[index]
)));
setState(() {
homeProvider.listDataMahasiswa();
});
},
title: Text(
homeProvider.listMahasiswa?[index].namaMahasiswa ??
'',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold),
),
subtitle: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(homeProvider
.listMahasiswa?[index].nohpMahasiswa ??
''),
Text(homeProvider
.listMahasiswa?[index].alamatMahasiswa ??
''),
Text(homeProvider.listMahasiswa?[index]
.pendidikan ??
''),
],
),
trailing: IconButton(
onPressed: () async {
await homeProvider.deleteMahasiswa(
context,
homeProvider.listMahasiswa?[index]
.idMahasiswa
.toString() ??
'');
},
icon: Icon(Icons.delete)),
),
),
);
},
)
),
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
await Navigator.push(context,
MaterialPageRoute(builder: (context) => FormPage(
isUpdate: false,
)));
setState(() {
homeProvider.listDataMahasiswa();
});
},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
child: Icon(Icons.add),
),
);
},
),
);
}
}

File Home Provider

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:flutter5/api/api_config.dart';
import 'package:flutter5/model/model_mahasiswa.dart';
import 'package:flutter5/network/network_provider.dart';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';

class HomeProvider extends ChangeNotifier {
List<DataMahasiswa>? listMahasiswa;
bool isLoading = true;

HomeProvider() {
init();
}

init() {
listDataMahasiswa();
}

Future<void> listDataMahasiswa() async {
isLoading = true;
notifyListeners();

try {
final response = await NetworkProvider().getDataMahasiswa();
Future.delayed(Duration(seconds: 3), () {
isLoading = false;
listMahasiswa = response.data ?? [];
notifyListeners();
});
} catch (e) {
print(e);
}
}
Future<void> deleteMahasiswa(BuildContext context, String idMahasiswa) async{
final response = await http.post(Uri.parse(ApiConfig.url + "delete-mahasiswa"), body: {
'id_mahasiswa': idMahasiswa,
});

var deletemahasiswa = await jsonDecode(response.body);
if(deletemahasiswa["status"] == 200){
listDataMahasiswa();
notifyListeners();
}else{
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("Hapus Gagal")));
}
}
}

File Form Page

import 'package:flutter/material.dart';
import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:flutter5/form/form_provider.dart';
import 'package:flutter5/model/model_mahasiswa.dart';
import 'package:provider/provider.dart';

class FormPage extends StatefulWidget {

final bool isUpdate;
final DataMahasiswa? data;

FormPage({Key? key, this.isUpdate = false, this.data}) : super(key: key);

@override
State<FormPage> createState() => _FormPageState();
}

class _FormPageState extends State<FormPage> {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => FormProvider(
widget.data?.idMahasiswa.toString() ?? '',
widget.data?.namaMahasiswa ?? '',
widget.data?.nohpMahasiswa ?? '',
widget.data?.alamatMahasiswa ?? '',
widget.data?.pendidikan ?? '',
),
child: Consumer<FormProvider>(
builder: (context, formProvider, child) {
return DefaultTabController(
length: 3,
child: Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: Text(
widget.data != null ? "Update Form" :
"Add Form"
),
bottom: TabBar(
tabs: [
Tab(child: Text("Biodata")),
Tab(child: Text("Pendidikan")),
Tab(child: Text("Pekerjaan")),
],
),
),
body: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: TabBarView(
children: [
// Form Biodata
Padding(
padding: EdgeInsets.all(20),
child: ListView(
children: [
Text("Nama"),
SizedBox(height: 15),
TextFormField(
controller: formProvider.isNamaCont,
decoration: InputDecoration(
filled: true,
fillColor: Colors.grey.withOpacity(0.2),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide.none)),
),
SizedBox(height: 25),
Text("No HP"),
SizedBox(height: 15),
TextFormField(
controller: formProvider.isNoHpCont,
keyboardType: TextInputType.phone,
decoration: InputDecoration(
filled: true,
fillColor: Colors.grey.withOpacity(0.2),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide.none)),
),
SizedBox(
height: 25,
),
Text("Alamat"),
SizedBox(height: 15),
TextFormField(
controller: formProvider.isAlamatCont,
decoration: InputDecoration(
filled: true,
fillColor: Colors.grey.withOpacity(0.2),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide.none)),
),
],
),
),

// Form Pendidikan
Padding(
padding: EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Pendidikan Terakhir"),
SizedBox(height: 15),
Container(
width: double.infinity,
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(10),
),
child: Padding(
padding: const EdgeInsets.all(10),
child: (DropdownButtonHideUnderline(
child: DropdownButton2(
hint: Text(
'Select Pendidikan',
style: TextStyle(
fontSize: 14,
color: Theme.of(context).hintColor,
),
),
items: formProvider.items
.map((item) => DropdownMenuItem<String>(
value: item,
child: Text(
item,
style: const TextStyle(
fontSize: 14,
),
),
))
.toList(),
value: widget.data != null ? formProvider.selectedValue : formProvider.selectedData,
onChanged: (value) {
setState(() {
if(widget.data != null){
formProvider.selectedValue = value;
}else{
formProvider.selectedData = value;
}
});
},
buttonStyleData: const ButtonStyleData(
height: 40,
width: 140,
),
menuItemStyleData: const MenuItemStyleData(
height: 40,
),
),
)),
),
)
],
),
),

// Form Pekerjaan
Scaffold(
body: Padding(
padding: EdgeInsets.all(20),
child: ListView(
children: [
Container(
child: ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: formProvider.listPekerjaan.length ?? 0,
itemBuilder: (context, index) {
return Card(
child: ListTile(
title: Row(
children: [
Text(formProvider.listPekerjaan[index]["nama_pekerjaan"] ?? ''),
SizedBox(width: 10),
Text(
"${formProvider.listPekerjaan[index]["lama"] ?? ''} Tahun",
style: TextStyle(color: Colors.grey),
)
],
),
trailing: IconButton(
onPressed: () {
setState(() {
formProvider.listPekerjaan.removeAt(index);
});
},
icon: Icon(Icons.close),
),
),
);
},
),
),
SizedBox(height: 20),
Card(
child: Padding(
padding: const EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Nama Pekerjaan"),
SizedBox(height: 10),
TextFormField(
controller: formProvider.isNamaPerkejaanCont,
decoration: InputDecoration(
fillColor: Colors.grey.withOpacity(0.2),
filled: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide.none)),
),
SizedBox(height: 15),
Text("Lama (Tahun)"),
SizedBox(
height: 10,
),
Container(
width: double.infinity,
height: 50,
decoration: BoxDecoration(
color: Colors.grey.withOpacity(0.1),
borderRadius: BorderRadius.circular(10),
),
child: Padding(
padding: const EdgeInsets.all(10),
child: Text("${formProvider.counter}", style: TextStyle(fontSize: 20),),
),
),
SizedBox(height: 10),
Row(
children: [
MaterialButton(
onPressed: () {
formProvider.minIncrements();
},
height: 50,
shape: OutlineInputBorder(
borderSide:
BorderSide(color: Colors.grey),
),
child: Icon(Icons.remove),
),
SizedBox(width: 10),
MaterialButton(
onPressed: () {
formProvider.addIncrements();
},
height: 50,
shape: OutlineInputBorder(
borderSide:
BorderSide(color: Colors.grey),
),
child: Icon(Icons.add),
),
],
),
SizedBox(height: 20),
MaterialButton(
onPressed: () {
formProvider.addDataPekerjaan(context);
},
color: Colors.blue,
height: 50,
minWidth: double.infinity,
child: Text(widget.data != null ? "Update" :
"Tambah",
style: TextStyle(color: Colors.white),
),
)
],
),
),
),
],
),
),
bottomNavigationBar: Padding(
padding: const EdgeInsets.all(20),
child: MaterialButton(
onPressed: () async {
widget.data != null
? formProvider.updateMahasiswa(context)
: await formProvider.addMahasiswa(context);
},
color: Colors.blue,
height: 65,
child: Text(widget.data != null ? "Update Data" :
"SIMPAN",
style: TextStyle(
color: Colors.white, fontWeight: FontWeight.bold),
),
),
),
),
],
),
),
));
},
),
);
}
}

File Form Provider

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:flutter5/api/api_config.dart';
import 'package:flutter5/model/list_model_pekerjaan.dart';
import 'package:flutter5/model/model_pekerjaan.dart';
import 'package:flutter5/network/network_provider.dart';
import 'package:http/http.dart' as http;

class FormProvider extends ChangeNotifier{

TextEditingController isNamaCont = TextEditingController();
TextEditingController isNoHpCont = TextEditingController();
TextEditingController isAlamatCont = TextEditingController();
TextEditingController isNamaPerkejaanCont = TextEditingController();

// Pendidikan
String? selectedValue;
String? selectedData;
final List<String> items = [
'SLTA / MA / SMK',
'SLTP/MTs',
'SDN / MIN',
'Tidak Sekolah',
];

// Pekerjaan
int counter = 1;
bool minus = false;
List<Map<String, String>> listPekerjaan = [];
var idmahasiswa;

FormProvider(String idMahasiswa, String nama, String nohp, String alamat, String pendidikan){
init(idMahasiswa, nama, nohp, alamat, pendidikan);
}

init(String idMahasiswa, String nama, String nohp, String alamat, String pendidikan){
idmahasiswa = idMahasiswa;
isNamaCont.text = nama;
isNoHpCont.text = nohp;
isAlamatCont.text = alamat;
selectedValue = pendidikan;


listDataPekerjaan();
}

void addIncrements(){
counter++;
minus = false;
notifyListeners();
}

void minIncrements(){
if(counter == 1){
minus = true;
}else{
minus = false;
counter--;
}
notifyListeners();
}

Future<void> addDataPekerjaan(BuildContext context) async{
listPekerjaan.add(
{
'nama_pekerjaan': isNamaPerkejaanCont.text,
'lama' : counter.toString(),
}
);
notifyListeners();
}

Future<void> listDataPekerjaan() async {
try{
final response = await NetworkProvider().getDataPekerjaan(idmahasiswa.toString());
listPekerjaan = (response.data ?? []).map((e) => {
'nama_pekerjaan': e.namaPekerjaan ?? '',
'lama' : e.lama?.toString() ?? '',
}).toList() ;
notifyListeners();
}catch(e){
print(e);
}
}

Future<void> addMahasiswa(BuildContext context) async{
final response = await http.post(Uri.parse(ApiConfig.url + "add-mahasiswa"), body: {
'nama_mahasiswa': isNamaCont.text,
'nohp_mahasiswa': isNoHpCont.text,
'alamat_mahasiswa': isAlamatCont.text,
'pendidikan': selectedData,
'pekerjaan': jsonEncode(listPekerjaan),
});

var addmahasiswa = await jsonDecode(response.body);

if(addmahasiswa["status"] == 200){
Navigator.pop(context);
}else{
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("Add Failed")));
}
}

Future<void> updateMahasiswa(BuildContext context) async{
final response = await http.post(Uri.parse(ApiConfig.url + "update-pekerjaan"), body: {
'id_mahasiswa': idmahasiswa,
'nama_mahasiswa': isNamaCont.text,
'nohp_mahasiswa': isNoHpCont.text,
'alamat_mahasiswa': isAlamatCont.text,
'pendidikan': selectedValue,
'pekerjaan': jsonEncode(listPekerjaan),
});

var updatemahasiswa = jsonDecode(response.body);

if(updatemahasiswa["status"] == 200){
Navigator.pop(context);
}else{
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("Update Failed")));
}

}





}