Eloquent ORM - 删除资料

删除资料

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"] });
+        },
+      }
+    );
   };

<<:  灵异现象 - 我根本没这个帐号阿

>>:  Day21 Metricbeat(二)

Unity与Photon的新手相遇旅途 | Day23-Photon房间场景

今天的内容为建立房间的场景以及离开房间Button。 ...

MacOS读取蓝牙摇杆讯号,利用python修改pynput程序码实现 - 1.起始

1. 前言: 之前想要实现在几公尺外遥控 mac book,於是就在虾皮上找到了这个蓝牙摇杆,虽然怀...

Day12 - 物理模拟篇 - 弹跳球世界III - 成为Canvas Ninja ~ 理解2D渲染的精髓

我们在上一次讲到用数理观点来观察反射行为的诸多细节,而这篇文则是要讲解斜向抛射。 不过因为斜向抛射的...

Day 30 - Make a Whack A Mole Game with Vanilla JS

前言 JS 30 是由加拿大的全端工程师 Wes Bos 免费提供的 JavaScript 简单应用...

Day 27 - 资料视觉化与API - 将资料转化成艺术

前言 觉得这个文章,花了太多时间在写但有些设定好像应该 更把他分的更清楚而不是一直只丢范例出来解释。...