iT邦幫忙

2021 iThome 鐵人賽

DAY 14
0
Modern Web

Laravel 實務筆記系列 第 14

Eloquent ORM - 刪除資料

  • 分享至 

  • xImage
  •  

刪除資料

Route::resource 建立的 DELETE API 設定上只能刪除一筆資料。

請求方法 路由 控制器函式 路由名稱標籤
DELETE /todos/{id} destroy todos.destroy

不過像 Todo 這種清單顯示的資料一筆筆刪也太麻煩了,所以這邊先實作批量刪除的功能。

首先新增一個路由

## /routes/web.php 
@@ -30,5 +30,6 @@ Route::get('/dashboard', [TodoController::class, 'index'])
 Route::resource('todo', TodoController::class);
+Route::put('todos', [TodoController::class,'delete'])->name('todos.delete');

在 TodoController 新增一個 delete 方法

## /app/Http/Controllers/TodoController.php
@@ -96,4 +96,13 @@ class TodoController extends Controller
     {
         //
     }
+
+
+    public function delete(Request $request )
+    {
+        $data = $request->all(); // 取得請求中的 body 資料
+        $todoIds = $data['ids'];
+        
+        Todo::destroy($todoIds);
+    }
 }

destroy 方法可以傳入主鍵陣列刪除對應的資料,像這邊就是傳入 todo 的 id 清單,整批刪除對應 id 的資料。

destroy 也能刪除單一 id 資料

Todo::destroy(1);

如果刪除資料不是根據主鍵而是其他條件,也可以在搜尋資料後呼叫 delete() 方法刪除。

// 搜尋 id 在 todoIds 陣列中的資料,批次刪除
Todo::whereIn('id', $todoIds )->delete(); 


// 也可以分段寫

$todoQuery = Todo::whereIn('id', $todoIds );
$todoQuery->delete(); 

更新畫面

幫清單加上勾選框

## /resources/js/Pages/Dashboard.js
@@ -10,6 +10,9 @@ import {
   Grid,
   IconButton,
   Box,
+  ListItemIcon,
+  ListItemButton,
+  Checkbox,
 } from "@mui/material";
 import { Head, Link, useForm } from "@inertiajs/inertia-react";
 import { Inertia } from "@inertiajs/inertia";
@@ -26,7 +29,7 @@ export default function Dashboard(props) {
   );
 
   const [todoList, setTodoList] = useState(
-    todos.map((todo) => ({ ...todo, editing: false }))
+    todos.map((todo) => ({ ...todo, editing: false, checked: false }))
   );
 
   const handleChange = (event) => {
@@ -82,6 +85,15 @@ export default function Dashboard(props) {
       }
     );
   };
+
+  const toggleCheck = (todoId) => {
+    const newList = todoList.map((todo) =>
+      todo.id === todoId ? { ...todo, checked: !todo.checked } : todo
+    );
+
+    setTodoList(newList);
+  };
+
   return (
     <Authenticated
       auth={props.auth}
@@ -133,6 +145,7 @@ export default function Dashboard(props) {
               <ListItem
                 button
                 key={item.id}
+                disablePadding
                 secondaryAction={
                   <IconButton
                     edge='end'
@@ -163,7 +176,21 @@ export default function Dashboard(props) {
                     }}
                   />
                 ) : (
-                  <ListItemText primary={item.name} />
+                  <ListItemButton
+                    role={undefined}
+                    onClick={() => toggleCheck(item.id)}
+                    dense>
+                    <ListItemIcon>
+                      <Checkbox
+                        edge='start'
+                        checked={item.checked}
+                        // tabIndex={-1}
+                        disableRipple
+                        // inputProps={{ "aria-labelledby": labelId }}
+                      />
+                    </ListItemIcon>
+                    <ListItemText primary={item.name} />
+                  </ListItemButton>
                 )}
               </ListItem>
             ))}

還需要一個發送刪除請求的按鈕,就設定成當有勾選的項目時 Add 按鈕會變成刪除按鈕吧

## /resources/js/Pages/Dashboard.js
@@ -1,4 +1,4 @@
-import React, { useState } from "react";
+import React, { useState, useMemo } from "react";
 import Authenticated from "@/Layouts/Authenticated";
 import {
   Container,
@@ -94,6 +94,15 @@ export default function Dashboard(props) {
     setTodoList(newList);
   };
 
+  const hasChecked = useMemo(
+    () => todoList.findIndex((todo) => todo.checked) >= 0,
+    [todoList]
+  );
+
+  const requestDelete = () => {
+    // 發送刪除請求
+  };
+
   return (
     <Authenticated
       auth={props.auth}
@@ -130,13 +139,23 @@ export default function Dashboard(props) {
               variant='standard'
               style={{ marginRight: 4 }}
             />
-            <Button
-              type='submit'
-              variant='contained'
-              color='primary'
-              disabled={processing}>
-              Add
-            </Button>
+            {hasChecked ? (
+              <Button
+                variant='contained'
+                color='error'
+                disabled={processing}
+                onClick={requestDelete}>
+                Delete
+              </Button>
+            ) : (
+              <Button
+                type='submit'
+                variant='contained'
+                color='primary'
+                disabled={processing}>
+                Add
+              </Button>
+            )}
           </Grid>
         </form>
         <Box sx={{ width: "100%", maxWidth: 360 }}>

加入刪除請求,用勾選項目的 id 陣列傳送刪除請求,一樣在請求結束後重新載入 todo 清單

@@ -100,7 +100,17 @@ export default function Dashboard(props) {
   );
 
   const requestDelete = () => {
-    console.log("Delete");
+    Inertia.put(
+      route("todos.delete"),
+      {
+        ids: todoList.filter((todo) => todo.checked).map((todo) => todo.id),
+      },
+      {
+        onFinish: (visit) => {
+          Inertia.reload({ only: ["todos"] });
+        },
+      }
+    );
   };

上一篇
Eloquent ORM - 編輯資料
下一篇
Eloquent ORM - 軟刪除
系列文
Laravel 實務筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言