ما هو DELETE فعلياً؟
في POST كنا نقول:
أنشئ منشوراً جديداًDartفي PUT كنا نقول:
عدّل المنشور الموجودDartأما DELETE فنقول:
احذف المنشور رقم 5Dartماذا نرسل للسيرفر؟
لاحظ أننا في DELETE غالباً لا نرسل Body.
في POST:
{
"title":"Flutter",
"body":"Learning Dio"
}Dartفي PUT:
{
"title":"New Title"
}Dartأما DELETE:
DELETE /posts/5Dartفقط.
لماذا لا نرسل Body؟
لأن السيرفر لا يحتاج بيانات جديدة.
هو يحتاج فقط معرفة:
من هو العنصر المطلوب حذفه؟Dartوهذه المعلومة موجودة في:
/posts/5Dartماذا يسمى الرقم 5؟
كما في PUT:
Path ParameterDartأو:
Resource IDDartالشكل الحقيقي
Flutter
│
▼
DELETE /posts/5
│
▼
Server
│
▼
Post Deleted
│
▼
200 OKDartإضافة دالة الحذف داخل ApiService
سنضيف:
Future<bool> deletePost(
int postId,
) async {
}Dartلماذا int فقط؟
لأننا لا نحتاج:
PostModelDartكامل.
نحتاج فقط:
idDartتنفيذ DELETE
Response response =
await dio.delete(Dartالرابط
'https://jsonplaceholder.typicode.com/posts/$postId'Dartإذا كان:
postId = 5Dartيصبح:
/posts/5Dartالكود
Future<bool> deletePost(
int postId,
) async {
Response response =
await dio.delete(
'https://jsonplaceholder.typicode.com/posts/$postId',
);
return response.statusCode == 200;
}Dartلماذا 200 ؟
لأن العملية نجحت.
بعض APIs تعيد:
204 No ContentDartأي:
تم الحذف
ولا يوجد محتوى راجعDartلكن jsonplaceholder يعيد 200.
كيف ننفذ الحذف من الشاشة؟
الطالب يجب أن يرى شيئاً مهماً:
قبل الحذف:
Post 1
Post 2
Post 3Dartبعد حذف Post 2:
Post 1
Post 3Dartبدون إعادة تشغيل التطبيق.
الزر
داخل Card أضف:
IconButton(
onPressed: () {
deletePost(post);
},
icon: const Icon(
Icons.delete,
),
)Dartلماذا لا نحذف مباشرة؟
خطأ شائع جداً.
المستخدم قد يضغط بالخطأ.
لذلك نضيف:
Confirmation DialogDartإظهار Dialog
showDialog(
context: context,
builder: (_) {
return AlertDialog(
title: const Text(
'Delete Post',
),
content: const Text(
'Are you sure?',
),
);
},
);Dartلماذا؟
أفضل ممارسة UX.
زر نعم
TextButton(
onPressed: () {
Navigator.pop(context);
deletePost(post);
},
child: const Text('Yes'),
)Dartزر إلغاء
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text('Cancel'),
)Dartتنفيذ الحذف
Future<void> deletePost(
PostModel post,
) async {
}Dartاستدعاء API
bool success =
await apiService.deletePost(
post.id,
);Dartإذا نجحت العملية
if(success){Dartحذف العنصر من القائمة المحلية
هذه أهم نقطة تعليمية.
كثير من المبتدئين يفعل:
await getPosts();Dartمن جديد.
لكن نحن سنفعل:
posts.removeWhere(
(element) =>
element.id == post.id,
);Dartماذا تفعل removeWhere ؟
لنفترض:
[
id=1,
id=2,
id=3,
]Dartنحذف:
id=2Dartتصبح:
[
id=1,
id=3,
]Dartتحديث الشاشة
setState(() {});Dartرسالة نجاح
ScaffoldMessenger.of(
context,
).showSnackBar(
const SnackBar(
content: Text(
'Post Deleted Successfully',
),
),
);Dartماذا تعلم الطالب هنا؟
HTTP
✅ DELETE Method
✅ Path Parameter
✅ Resource ID
Dio
✅ dio.delete()
✅ Response بعد الحذف
Flutter
✅ AlertDialog
✅ Confirmation
✅ removeWhere
✅ تحديث القائمة محلياً
نقطة احترافية مهمة جداً
بعد POST تعلمنا:
Model → toJson → ServerDartبعد PUT تعلمنا:
Model → toJson → UpdateDartأما DELETE فهو أول Request لا يحتاج:
toJson()Dartولا يحتاج:
fromJson()Dartلأننا لا نرسل بيانات ولا نستقبل بيانات.
بل نرسل:
ID فقطDartوهذه نقطة ممتازة لشرح أن كل HTTP Method لها احتياجات مختلفة:
GET
↓
استقبال بيانات
↓
fromJson()
POST
↓
إرسال بيانات
↓
toJson()
PUT
↓
تعديل بيانات
↓
toJson()
DELETE
↓
إرسال ID فقط
↓
لا يحتاج ModelDartالكود كامل:
سنعدل ملفين فقط:
api_service.dart
posts_page.dartDartأولاً: api_service.dart
سنضيف دالة الحذف فقط.
/*
==================================================
DELETE POST
==================================================
تستقبل:
postId
لماذا؟
لأن السيرفر يحتاج معرفة
أي منشور سيتم حذفه.
لا نحتاج إرسال PostModel كامل.
DELETE Request غالباً
لا يحتوي Body.
بل يعتمد على ID الموجود
داخل الرابط.
*/
Future<bool> deletePost(int postId) async {
/*
إرسال DELETE Request
إذا كان postId = 5
سيصبح الرابط:
/posts/5
*/
Response response =
await dio.delete(
'https://jsonplaceholder.typicode.com/posts/$postId',
);
/*
إذا نجحت العملية
يعيد السيرفر 200.
بعض APIs تعيد 204.
لكن jsonplaceholder
تعيد 200.
*/
return response.statusCode == 200;
}Dartثانياً: posts_page.dart
إضافة Dialog تأكيد الحذف
داخل _PostsPageState
أضف:
/*
==================================================
SHOW DELETE DIALOG
==================================================
قبل الحذف نعرض نافذة تأكيد.
لماذا؟
لأن المستخدم قد يضغط
زر الحذف بالخطأ.
وهذه تعتبر Best Practice.
*/
Future<void> showDeleteDialog(PostModel post) async {
showDialog(
context: context,
builder: (_) {
return AlertDialog(
title: const Text(
'Delete Post',
),
content: const Text(
'Are you sure you want to delete this post?',
),
actions: [
/*
إلغاء العملية
*/
TextButton(
onPressed: () {
Navigator.pop(
context,
);
},
child: const Text(
'Cancel',
),
),
/*
تأكيد الحذف
*/
TextButton(
onPressed: () {
Navigator.pop(
context,
);
deletePost(
post,
);
},
child: const Text(
'Delete',
),
),
],
);
},
);
}Dartإضافة دالة الحذف
داخل _PostsPageState
أضف:
/*
==================================================
DELETE POST
==================================================
تنفذ عملية الحذف
من السيرفر.
ثم تحذف العنصر
من القائمة المحلية.
*/
Future<void> deletePost(PostModel post) async {
bool success =
await apiService.deletePost(
post.id,
);
if (success) {
/*
حذف العنصر محلياً.
لماذا؟
حتى يتم تحديث الواجهة
مباشرة دون إعادة تحميل
جميع المنشورات.
*/
posts.removeWhere(
(element) {
return element.id ==
post.id;
},
);
/*
إعادة بناء الواجهة.
*/
setState(() {});
/*
رسالة نجاح.
*/
ScaffoldMessenger.of(
context,
).showSnackBar(
const SnackBar(
content: Text(
'Post Deleted Successfully',
),
),
);
} else {
ScaffoldMessenger.of(
context,
).showSnackBar(
const SnackBar(
content: Text(
'Failed To Delete Post',
),
),
);
}
}Dartإضافة زر الحذف داخل Card
ابحث عن:
return Card(Dartوداخل الـ Column أضف:
const SizedBox(
height: 10,
),Dartثم:
Row(
children: [
/*
زر التعديل
*/
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) =>
EditPostPage(
post: post,
),
),
);
},
child: const Text(
'Edit',
),
),
const SizedBox(
width: 10,
),
/*
زر الحذف
*/
ElevatedButton(
onPressed: () {
showDeleteDialog(
post,
);
},
child: const Text(
'Delete',
),
),
],
),Dartماذا تعلم الطالب من ميزة الحذف؟
HTTP
DELETE MethodDartDio
dio.delete(...)DartFlutter
AlertDialogDartshowDialog(...)DartremoveWhere(...)DartBest Practice
❌ لا تحذف مباشرة عند الضغط.
onPressed: deletePostDartهذا غير احترافي.
✅ اعرض Dialog أولاً.
showDeleteDialog()Dartثم:
deletePost()Dartأفضل نقطة تعليمية هنا
لاحظ الفرق بين العمليات الأربع:
GET
↓
fromJson()
POST
↓
toJson()
PUT
↓
toJson()
DELETE
↓
ID فقطDartولهذا تعتبر DELETE أبسط HTTP Method ضمن CRUD لأنها لا تحتاج Body ولا Model جديد، بل تحتاج فقط معرف العنصر المطلوب حذفه.