Tutorial CRUD Flutter PHP dan MySQL Part Kedua Membuat Mobile App

Share:
Tutorial CRUD Flutter PHP dan MySQL Part Kedua Membuat Mobile App
Halo semuanya, kembali lagi di sahretech. Pada kesempatan kali ini kita akan belajar membuat aplikasi catatan(note app) sederhana menggunakan flutter, php dan mysql. Tutorial ini saya bagi menjadi 2 bagian. Bagian pertama pembuatan back-end dan bagian kedua pembuatan aplikasi mobile. Ikuti pembahasannya di bawah ini.



Studi Kasus

Kita akan membuat aplikasi catatan sederhana yang dapat melakukan operasi CRUD. Tampilan aplikasi ini cukup sederhana, dimana kita menggunakan masonry grid view untuk membuat tampilan card yang bertumpuk di setiap baris dengan 2 ukuran yang berbeda. Di bawah ini adalah UI akhir dari tulisan ini.

Aplikasi CRUD Flutter
Hasil Akhir


Membuat Aplikasi Catatan dengan Flutter

Setelah kita membuat back-end di artikel sebelumnya, https://www.sahretech.com/2022/03/crud-flutter-php-mysql-pertama.html. Kali ini kita akan mulai membuat tampilan dan proses aplikasi mobile dengan flutter.

1. Buatlah sebuah project flutter baru dengan nama note_app_mysql atau dengan nama bebas.

2. Buka file pubspec.yaml. Lalu tambahkan library flutter_staggered_grid_view: ^0.6.1 dan http: ^0.13.4 kemudian tekan ctrl + s untuk mendownload library yang dibutuhkan.

pubspec.yaml



3. Buka main.dart, lalu edit script di dalamnya dengan script di bawah ini.
    

// ignore_for_file: use_key_in_widget_constructors, prefer_const_constructors import 'package:flutter/material.dart'; import 'home.dart'; void main() => runApp(App()); class App extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, // themeMode: ThemeMode.dark, theme: ThemeData( primaryColor: Colors.black, scaffoldBackgroundColor: Colors.blueGrey.shade900, appBarTheme: AppBarTheme( backgroundColor: Colors.transparent, elevation: 0 ) ), title: 'Flutter + PHP CRUD', initialRoute: '/', routes: { '/': (context) => Home(), }, ); } }


4. Buatlah sebuah file baru di dalam folder lib dengan nama home.dart. Lalu ikuti scriptnya seperti di bawah ini. Jangan lupa untuk mengganti http://192.168.100.221 menjadi ip komputer kalian masing-masing.
    

// ignore_for_file: prefer_const_constructors, unused_import, prefer_const_literals_to_create_immutables, use_key_in_widget_constructors, prefer_final_fields, unused_field, avoid_print, unnecessary_null_comparison, prefer_is_empty, unused_local_variable import 'package:flutter/material.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; import 'add.dart'; import 'edit.dart'; class Home extends StatefulWidget { @override HomeState createState() => HomeState(); } class HomeState extends State<Home> { //make list variable to accomodate all data from database List _get = []; //make different color to different card final _lightColors = [ Colors.amber.shade300, Colors.lightGreen.shade300, Colors.lightBlue.shade300, Colors.orange.shade300, Colors.pinkAccent.shade100, Colors.tealAccent.shade100 ]; @override void initState() { super.initState(); //in first time, this method will be executed _getData(); } Future _getData() async { try { final response = await http.get(Uri.parse( //you have to take the ip address of your computer. //because using localhost will cause an error "http://192.168.1.4/latihan/note_app/list.php")); // if response successful if (response.statusCode == 200) { final data = jsonDecode(response.body); // entry data to variabel list _get setState(() { _get = data; }); } } catch (e) { print(e); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Note List'), ), //if not equal to 0 show data //else show text "no data available" body: _get.length != 0 //we use masonry grid to make masonry card style ? MasonryGridView.count( crossAxisCount: 2, itemCount: _get.length, itemBuilder: (context, index) { return GestureDetector( onTap: () { Navigator.push( context, //routing into edit page //we pass the id note MaterialPageRoute(builder: (context) => Edit(id: _get[index]['id'],))); }, child: Card( //make random color to eveery card color: _lightColors[index % _lightColors.length], child: Container( //make 2 different height constraints: BoxConstraints(minHeight: (index % 2 + 1) * 85), padding: EdgeInsets.all(15), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '${_get[index]['date']}', style: TextStyle(color: Colors.black), ), SizedBox(height: 10), Text( '${_get[index]['title']}', style: TextStyle( color: Colors.black, fontSize: 20, fontWeight: FontWeight.bold, ), ), ], ), ), ), ); }, ) : Center( child: Text( "No Data Available", style: TextStyle( color: Colors.white, fontSize: 20, fontWeight: FontWeight.bold, ), ), ), floatingActionButton: FloatingActionButton( backgroundColor: Colors.black, child: Icon(Icons.add), onPressed: () { Navigator.push( context, //routing into add page MaterialPageRoute(builder: (context) => Add())); }, ), ); } }



5. Buatlah sebuah file baru di dalam folder lib dengan nama add.dart. Lalu ikuti scriptnya seperti di bawah ini. Jangan lupa untuk mengganti http://192.168.100.221 menjadi ip komputer kalian masing-masing.
    

// ignore_for_file: unused_field, prefer_const_constructors, avoid_print import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; class Add extends StatefulWidget { const Add({Key? key}) : super(key: key); @override State<Add> createState() => _AddState(); } class _AddState extends State<Add> { final _formKey = GlobalKey<FormState>(); //inisialize field var title = TextEditingController(); var content = TextEditingController(); Future _onSubmit() async { try { return await http.post( Uri.parse("http://192.168.1.4/latihan/note_app/create.php"), body: { "title": title.text, "content": content.text, }, ).then((value) { //print message after insert to database //you can improve this message with alert dialog var data = jsonDecode(value.body); print(data["message"]); Navigator.of(context) .pushNamedAndRemoveUntil('/', (Route<dynamic> route) => false); }); } catch (e) { print(e); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Create New Note"), ), body: Form( key: _formKey, child: Container( padding: EdgeInsets.all(20.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Title', style: TextStyle( color: Colors.white, fontSize: 16, fontWeight: FontWeight.bold, ), ), SizedBox(height: 5), TextFormField( controller: title, decoration: InputDecoration( hintText: "Type Note Title", border: OutlineInputBorder( borderRadius: BorderRadius.circular(15.0), ), fillColor: Colors.white, filled: true), style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 16, ), validator: (value) { if (value!.isEmpty) { return 'Note Title is Required!'; } return null; }, ), SizedBox(height: 20), Text( 'Content', style: TextStyle( color: Colors.white, fontSize: 16, fontWeight: FontWeight.bold, ), ), SizedBox(height: 5), TextFormField( controller: content, keyboardType: TextInputType.multiline, minLines: 5, maxLines: null, decoration: InputDecoration( hintText: 'Type Note Content', border: OutlineInputBorder( borderRadius: BorderRadius.circular(15.0), ), fillColor: Colors.white, filled: true), style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 16, ), validator: (value) { if (value!.isEmpty) { return 'Note Content is Required!'; } return null; }, ), SizedBox(height: 15), ElevatedButton( style: ElevatedButton.styleFrom( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(15), ), ), child: Text( "Submit", style: TextStyle(color: Colors.white), ), onPressed: () { //validate if (_formKey.currentState!.validate()) { //send data to database with this method _onSubmit(); } }, ) ], ), ), ), ); } }


6. Buatlah sebuah file baru di dalam folder lib dengan nama edit.dart. Lalu ikuti scripnya seperti di bawah ini. Jangan lupa untuk mengganti http://192.168.100.221 menjadi ip komputer kalian masing-masing


// ignore_for_file: unused_field, prefer_const_constructors, avoid_print, use_key_in_widget_constructors, must_be_immutable, unused_element, unused_local_variable, avoid_unnecessary_containers import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; class Edit extends StatefulWidget { Edit({required this.id}); String id; @override State<Edit> createState() => _EditState(); } class _EditState extends State<Edit> { final _formKey = GlobalKey<FormState>(); //inisialize field var title = TextEditingController(); var content = TextEditingController(); @override void initState() { super.initState(); //in first time, this method will be executed _getData(); } //Http to get detail data Future _getData() async { try { final response = await http.get(Uri.parse( //you have to take the ip address of your computer. //because using localhost will cause an error //get detail data with id "http://192.168.1.4/latihan/note_app/detail.php?id='${widget.id}'")); // if response successful if (response.statusCode == 200) { final data = jsonDecode(response.body); setState(() { title = TextEditingController(text: data['title']); content = TextEditingController(text: data['content']); }); } } catch (e) { print(e); } } Future _onUpdate(context) async { try { return await http.post( Uri.parse("http://192.168.1.4/latihan/note_app/update.php"), body: { "id": widget.id, "title": title.text, "content": content.text, }, ).then((value) { //print message after insert to database //you can improve this message with alert dialog var data = jsonDecode(value.body); print(data["message"]); Navigator.of(context) .pushNamedAndRemoveUntil('/', (Route<dynamic> route) => false); }); } catch (e) { print(e); } } Future _onDelete(context) async { try { return await http.post( Uri.parse("http://192.168.1.4/latihan/note_app/delete.php"), body: { "id": widget.id, }, ).then((value) { //print message after insert to database //you can improve this message with alert dialog var data = jsonDecode(value.body); print(data["message"]); // Remove all existing routes until the home.dart, then rebuild Home. Navigator.of(context) .pushNamedAndRemoveUntil('/', (Route<dynamic> route) => false); }); } catch (e) { print(e); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Creat New Note"), // ignore: prefer_const_literals_to_create_immutables actions: [ Container( padding: EdgeInsets.only(right: 20), child: IconButton( onPressed: () { showDialog( context: context, builder: (BuildContext context) { //show dialog to confirm delete data return AlertDialog( content: Text('Are you sure you want to delete this?'), actions: <Widget>[ ElevatedButton( child: Icon(Icons.cancel), onPressed: () => Navigator.of(context).pop(), ), ElevatedButton( child: Icon(Icons.check_circle), onPressed: () => _onDelete(context), ), ], ); }, ); }, icon: Icon(Icons.delete)), ) ], ), body: Form( key: _formKey, child: Container( padding: EdgeInsets.all(20.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Title', style: TextStyle( color: Colors.white, fontSize: 16, fontWeight: FontWeight.bold, ), ), SizedBox(height: 5), TextFormField( controller: title, decoration: InputDecoration( hintText: "Type Note Title", border: OutlineInputBorder( borderRadius: BorderRadius.circular(15.0), ), fillColor: Colors.white, filled: true), style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 16, ), validator: (value) { if (value!.isEmpty) { return 'Note Title is Required!'; } return null; }, ), SizedBox(height: 20), Text( 'Content', style: TextStyle( color: Colors.white, fontSize: 16, fontWeight: FontWeight.bold, ), ), SizedBox(height: 5), TextFormField( controller: content, keyboardType: TextInputType.multiline, minLines: 5, maxLines: null, decoration: InputDecoration( hintText: 'Type Note Content', border: OutlineInputBorder( borderRadius: BorderRadius.circular(15.0), ), fillColor: Colors.white, filled: true), style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 16, ), validator: (value) { if (value!.isEmpty) { return 'Note Content is Required!'; } return null; }, ), SizedBox(height: 15), ElevatedButton( style: ElevatedButton.styleFrom( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(15), ), ), child: Text( "Submit", style: TextStyle(color: Colors.white), ), onPressed: () { //validate if (_formKey.currentState!.validate()) { //send data to database with this method _onUpdate(context); } }, ) ], ), ), ), ); } }


Semua step sudah kita lalui, dan untuk penjelasannya sudah saya sertakan di dalam script di atas. Jangan lupa juga untuk mengganti setiap ip address 192.168.100.221 menjadi ip address komputer kalian masing-masing. Silahkan bertanya di kolom komentar di bawah ini jika ada kendala. Ok , sekarang waktunya kita lakukan uji coba. Jika semua step di atas berhasil dikerjakan maka tampilannya akan tampak seperti gambar di bawah ini.

Note App Flutter
Hasil Akhir



Nah sekarang kalian sudah bisa membuat CRUD dengan menggunakan flutter, php, dan mysql. Selanjutnya kalian bisa melakukan improvisasi dengan menggunakan model dan state management agar aplikasi yang dibangun lebih efisien dan mudah di-maintenance.

Tutorial ini juga bisa kalian kembangkan untuk membuat berbagai macam aplikasi yang membuatuhkan crud dasar seperti aplikasi pendataan, kontak, penilaian dan semacamnya.



Ok, sekian tutorial kita kali ini tentang Tutorial CRUD Flutter PHP dan MySQL Part Kedua. Semoga bermanfaat, jika ada kendala silahkan tanya langsung di kolom komentar atau bertanya langsung di fanspage sahretech. Sekian dan terima kasih.

10 comments:

  1. cara runnning nya gimana bang?

    ReplyDelete
    Replies
    1. Hidupin emulator, trus tekan F5. Klo belum ada emulator bisa pake chrome, atau hp beneran.

      Delete
  2. Bang nanya, sudah bisa run app. jalan tapi muncul error XMLHttpRequest error. solusinya gimana ya udah cari - cari masih gak nemu

    ReplyDelete
    Replies
    1. coba tambah script ini mas di setelah url endpoint

      headers: {
      "Accept": "application/json",
      "Access-Control_Allow_Origin": "*"
      });

      Delete
    2. yang ini penempatanya bagian mana ya mas? punya saya jalan tapi ada error seperti komentar yang ini

      Delete
  3. Replies
    1. iya mas gk ada, ini fokusnya di crud. klo pencarian ada contohnya di tutorial fluuter saya yang ini https://www.sahretech.com/2022/02/cara-mudah-membuat-fitur-pencarian-flutter.html

      Delete
  4. gan itu flutter nya versi berapa ya...

    ReplyDelete

Jangan lupa kasih komentar ya!. Karena komentar kalian membantu kami menyediakan informasi yang lebih baik