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