- 7 Màu
- about
- Ajax
- ảnh
- Ảnh b tháng 4
- Ảnh Bìa
- Ảnh bìa ca sĩ
- Ảnh bìa Facebook
- Ảnh bìa gái đẹp
- Ảnh bìa giáng sinh
- ảnh bìa liên minh huyền thoại
- Ảnh bìa năm mới
- Ảnh bìa tháng 10
- Ảnh bìa tháng 11
- Ảnh bìa tháng 12
- Ảnh bìa tháng 4
- Ảnh bìa tháng 8
- Ảnh bìa tháng 9
- Ảnh chế
- Ảnh chibi
- Ảnh Đẹp
- Ảnh động
- asp.net core
- ASP.NET Core Identity
- asp.net mvc
- backend
- Blogger Templates
- blogspot
- Brush
- Cafe Code
- Christmas
- Chữ nghệ thuật
- Chúc mừng năm mới
- Chuyện tình bác sĩ
- Cô Đơn
- Code
- css
- Dame
- Double Exposure
- Download
- Ebook
- EPPlus
- Faq
- File 3D
- flutter
- Font chữ
- Font chữ việt hóa
- frontend
- Fshare.vn
- Giáng sinh
- Hacker
- Hacking
- Halloween
- Hiệu ứng chữ
- Hình nền máy tính
- học javascript
- Hot Girl
- HTML - CSS - ?
- html/css
- Hướng dẫn cover ảnh bìa
- Hướng dẫn Photoshop
- javascript
- javascript dom
- Khung ảnh bìa
- Khung Hình
- Kĩ năng seo
- lập trình asp.net
- lập trình mobile
- Logo
- Mặt Nạ
- Mockup
- ngày nhà giáo Việt Nam
- Ngày phụ nữ
- Noel
- Phần Mềm
- Phiêu Lưu
- Phím tắt
- Photoshop
- PNG
- Pokémon
- PSD
- PSD 3D Text
- PSD ảnh bìa
- psd đường một chiều
- Seo
- service
- Soái Ca
- Sơn Tùng M-TP
- source code
- Stock Ảnh
- Sự kiện Blogger
- Tâm Trạng
- tản mạn
- Tất cả bài viết
- template
- template chuẩn seo
- templates đẹp
- Tết
- Tết trung thu
- Text Effect
- Thầy cô
- Thủ Thuật
- Thủ thuật Blogger
- Thủ thuật Facebook
- Thủ thuật Photoshop
- Tiện ích Blogger
- Tìm hiểu về Photoshop
- Tình Yêu
- Tutorial
- Typo
- Typography
- ui ux design
- Valentine
- Vector
- Video
CRUD Data in Flutter #2 Thêm sửa xóa dữ liệu
Trong bài trước, chúng ta đã thực hiện việc call, fetch API và hiển thị dữ liệu trên UI. Hôm nay chúng ta cùng hoàn thiện các chức năng còn lại trong series này nhé, thêm sửa xóa dữ liệu trong Flutter.
Ok, chúng ta cùng bắt đầu với từng chức năng, với các API có sẵn, mình đã giới thiệu ở bài trước.
Thêm mới dữ liệu
Tính năng sẽ được thực hiện lần này là tính năng thêm dữ liệu mới thông qua API đã được cung cấp. Nhiệm vụ của chúng ta là tạo một biểu mẫu đầu vào để người dùng có thể nhập dữ liệu họ muốn thêm vào. Tạo một tệp employee_add.dart bên trong một thư mục lib/pages và thêm code sau.
import 'package:flutter_crud_data/pages/employee.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../providers/employee_provider.dart';
class EmployeeAdd extends StatefulWidget {
@override
_EmployeeAddState createState() => _EmployeeAddState();
}
class _EmployeeAddState extends State<EmployeeAdd> {
//COMMENT-3: DEFINE VARIABLE
void submit(BuildContext context) {
//COMMENT-2 LƯU DỮ LIỆU
}
@override
Widget build(BuildContext context) {
return Scaffold(
key: snackbarKey,
appBar: AppBar(
title: Text('Add Employee'),
actions: <Widget>[
FlatButton(
child: Icon(
Icons.save,
color: Colors.white,
),
onPressed: () => submit(context),
)
],
),
body: Container(
margin: EdgeInsets.all(10),
child: ListView(
children: <Widget>[
//COMMENT-1
],
),
),
);
}
}
* Lưu ý: Các bạn cần lưu ý các vị trí của các comment, sẽ cần cho các bước sau.Giải thích: Cấu trúc đoạn mã trên sẽ hiển thị một Appbar với tiêu đề và một nút để lưu trữ dữ liệu.
Khi nhấn vào nút (+) nó sẽ chuyển sang trang khác, để thực hiện, ta mở tệp lib/pages/employee.dart, sửa đổi mã sau thành.
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.pink,
child: Text('+'),
onPressed: () {
Navigator.of(context)
.push(MaterialPageRoute(builder: (context) => EmployeeAdd()));
},
),
Và đừng quên import:
import './employee_add.dart';
Trở lại lib/pages/employee_add.dart, thêm code sau đang để tạo ra các TextField (các input để nhập dữ liệu). Thay thế COMMENT-1 bằng code sau:
TextField(
controller: _name,
decoration: InputDecoration(
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Colors.pinkAccent,
),
),
hintText: 'Họ tên',
),
onSubmitted: (_) {
FocusScope.of(context).requestFocus(salaryNode);
},
),
TextField(
controller: _salary,
focusNode: salaryNode,
decoration: InputDecoration(
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Colors.pinkAccent,
),
),
hintText: 'Mức lương',
),
onSubmitted: (_) {
FocusScope.of(context).requestFocus(ageNode);
},
),
TextField(
controller: _age,
focusNode: ageNode,
decoration: InputDecoration(
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Colors.pinkAccent,
),
),
hintText: 'Tuổi',
),
),
Thay thế COMMENT-3 bằng code sau:
final TextEditingController _name = TextEditingController();
final TextEditingController _salary = TextEditingController();
final TextEditingController _age = TextEditingController();
final snackbarKey = GlobalKey<ScaffoldState>();
FocusNode salaryNode = FocusNode();
FocusNode ageNode = FocusNode();
Còn đối với hàm xử lý quá trình thêm dữ liệu, mở tệp lib/providers/employee_provider.dart và tạo phương thức mới theo đoạn mã sau
Future<bool> storeEmployee(String name, String salary, String age) async {
final url = 'http://employee-crud-flutter.daengweb.id/add.php';
final response = await http.post(url, body: {
'employee_name': name,
'employee_salary': salary,
'employee_age': age
});
final result = json.decode(response.body);
if (response.statusCode == 200 && result['status'] == 'success') {
notifyListeners();
return true;
}
return false;
}
Để sử dụng chức năng trên, hãy mở lại tệp employee_add.dart và sửa đổi phương thức submit() thành.
void submit(BuildContext context) {
Provider.of<EmployeeProvider>(context, listen: false)
.storeEmployee(_name.text, _salary.text, _age.text)
.then((res) {
if (res) {
Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (context) => Employee()));
} else {
}
});
}
Lưu lại và chạy để xem kết quả.Chỉnh sửa dữ liệu
Bước đầu tiên để hoàn thành tính năng này là tạo một tệp mới sẽ xử lý dữ liệu chỉnh sửa từ biểu mẫu, tạo tệp có tên employee_edit.dart trong thư mục lib/pages và thêm code sau:
import 'package:flutter_crud_data/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;
EmployeeEdit({this.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();
@override
void initState() {
Future.delayed(Duration.zero, () {
Provider.of<EmployeeProvider>(context, listen: false).findEmployee(widget.id).then((response) {
_name.text = response.employeeName;
_salary.text = response.employeeSalary;
_age.text = response.employeeAge;
});
});
super.initState();
}
void submit(BuildContext context) {
if (!_isLoading) {
setState(() {
_isLoading = true;
});
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 {
}
});
}
}
@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: 'Họ tên',
),
onSubmitted: (_) {
FocusScope.of(context).requestFocus(salaryNode);
},
),
TextField(
controller: _salary,
focusNode: salaryNode,
decoration: InputDecoration(
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Colors.pinkAccent,
),
),
hintText: 'Mức lương',
),
onSubmitted: (_) {
FocusScope.of(context).requestFocus(ageNode);
},
),
TextField(
controller: _age,
focusNode: ageNode,
decoration: InputDecoration(
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Colors.pinkAccent,
),
),
hintText: 'Tuổi',
),
),
],
),
),
);
}
}
Sau đó mở tập tin lib/pages/employee.dart và quấn widget Card() bên ListView.build() vào:
return ListView.builder(
itemCount: data.dataEmployee.length,
itemBuilder: (context, i) {
return ListView.builder(
itemCount: data.dataEmployee.length,
itemBuilder: (context, i) {
return InkWell(
onTap: () {
Navigator.of(context).push(
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(
'Tuổi: ${data.dataEmployee[i].employeeAge}'),
trailing: Text(
"Lương: ${data.dataEmployee[i].employeeSalary}"),
),
),
);
},
);
},
);
Và đừng quên import
import './employee_edit.dart';
Chức năng xử lý tìm kiếm dữ liệu nhân viên theo id là thêm đoạn code bên dưới vào tệp lib/providers/employee_provider.dart
Future<EmployeeModel> findEmployee(String id) async {
return _data.firstWhere((i) => i.id == id);
}
Và tiếp tục thêm code sau bên dưới:
Future<bool> updateEmployee(id, name, salary, age) async {
final url = 'http://employee-crud-flutter.daengweb.id/update.php';
final response = await http.post(url, body: {
'id': id,
'employee_name': name,
'employee_salary': salary,
'employee_age': age
});
final result = json.decode(response.body);
if (response.statusCode == 200 && result['status'] == 'success') {
notifyListeners();
return true;
}
return false;
}
Ta lưu lại và chạy thử: Để chỉnh sửa các item, ta nhấp vào item đó để chỉnh sửa:
Xóa dữ liệu
Có hai giai đoạn để hoàn thành chức năng xóa dữ liệu, trong đó bước đầu tiên là loại bỏ bằng hộp thoại xác nhận và bước thứ hai là chức năng đưa ra yêu cầu đối với API. Mở tệp lib/pages/employee.dart và bọc Card() bên trong ListView.builder() bằng tiện ích Dismissible.
child: Dismissible(
key: UniqueKey(),
direction: DismissDirection.endToStart,
confirmDismiss: (DismissDirection direction) async {
final bool res = await showDialog(context: context, builder: (BuildContext context) {
return AlertDialog(
title: Text('Xác nhận'),
content: Text('Bạn có chắc muốn xóa item này?'),
actions: <Widget>[
FlatButton(onPressed: () => Navigator.of(context).pop(true), child: Text('Xóa'),),
FlatButton(onPressed: () => Navigator.of(context).pop(false), child: Text('Hủy bỏ'),)
],
);
});
return res;
},
onDismissed: (value) {
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(
'Tuổi: ${data.dataEmployee[i].employeeAge}'),
trailing: Text(
"Lương: ${data.dataEmployee[i].employeeSalary}"),
),
),
),
Cuối cùng là tạo một hàm để thực hiện các request đến server dựa trên API đã được xác định. Mở tệp employee_provider.dart và thêm phương thức sau
Future<void> deleteEmployee(String id) async {
final url = 'http://employee-crud-flutter.daengweb.id/delete.php';
await http.get(url + '?id=$id');
}
Lưu lại và chạy thử, ta thực hiện xóa bằng cách lướt item sang trái và xác nhận để xóa:
Lời kết
Và cuối cùng mình sẽ kết thúc series CRUD data trong Flutter tại đây, các bước thực hiện khá là đơn giản, nhưng vẫn còn nhiều cách mới hơn để thực hiện CRUD. Và cụ thể sắp tới làm sẽ tiếp tục với series với hơn, với cách mới hơn, và rút gọn nhiều thời gian hơn.
Mong series này hữu ích với bạn. Chúc các bạn thành công.
By Hiếu Quốc.
Có lẽ bạn thích?
10 comments
Danh Mục
Blog Bạn Bè
Comments
Địa chỉ
52 Xô Viết Nghệ Tĩnh, Hải Châu, Đà Nẵng
A mới comback :v rãnh ghé a chơi nha :v
ReplyDeleteoce anh trai 🙌
DeleteThích cái countdown kia ghê :V
ReplyDeletethích thì rip :v
Deletenếu bạn thích thì ib mình gửi widget cho nhé
DeleteMình xin cái countdown được ko ạ lecanhduc.hutech@gmail.com
ReplyDeleteChào bạn, mình gửi bạn bài viết nhé.
Deletehttps://www.quochieu.com/2021/01/share-widget-em-nguoc-tet-2021-cho-blogger.html
Footer mobile lỗi kìa em
ReplyDeletecảm ơn anh nhé. blog em cũng đang maintain 🙌
DeleteAnh cho em xin code với ạ
ReplyDeletebuicanhcntt138@gmail.com