You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Laravel单个Blade视图中创建Todo-List及其关联多事项?

How to Create a Todo List with Multiple Items in a Single Blade Form (Single Submit)

Got it, let's walk through exactly how to build this. We'll use Laravel's model relationships, form array inputs, and a single controller action to save both the list and its items in one go—no multiple submissions needed.

1. Set Up Models & Relationships

First, make sure your models are wired up with the correct one-to-many relationship (a todo list has many items, each item belongs to one list).

TodoList Model

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;

class TodoList extends Model
{
    protected $fillable = ['name'];

    // Define relationship to TodoItem
    public function items(): HasMany
    {
        return $this->hasMany(TodoItem::class);
    }
}

TodoItem Model

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class TodoItem extends Model
{
    protected $fillable = ['description', 'completed'];

    // Define relationship to TodoList
    public function todoList(): BelongsTo
    {
        return $this->belongsTo(TodoList::class);
    }
}

2. Create Database Migrations

If you haven't already, create the necessary tables to store your lists and items:

TodoLists Migration

Schema::create('todo_lists', function (Blueprint $table) {
    $table->id();
    $table->string('name'); // Stores the todo list name
    $table->timestamps();
});

TodoItems Migration

Schema::create('todo_items', function (Blueprint $table) {
    $table->id();
    $table->foreignId('todo_list_id')->constrained()->onDelete('cascade'); // Links to the parent list
    $table->text('description'); // The todo item text
    $table->boolean('completed')->default(false); // Optional: track completion status
    $table->timestamps();
});

Run php artisan migrate to apply these tables to your database.

3. Controller Logic (Store Action)

In your TodoListController, add a store method that first saves the parent list, then bulk-saves all associated items.

<?php

namespace App\Http\Controllers;

use App\Models\TodoList;
use Illuminate\Http\Request;

class TodoListController extends Controller
{
    public function store(Request $request)
    {
        // Validate incoming form data
        $validated = $request->validate([
            'todo_list.name' => 'required|string|max:255',
            'items' => 'required|array|min:1', // Ensure at least one item is submitted
            'items.*.description' => 'required|string|max:500',
        ]);

        // Step 1: Create the parent Todo List
        $todoList = TodoList::create($validated['todo_list']);

        // Step 2: Prepare items with the parent list ID
        $items = collect($validated['items'])->map(function ($item) use ($todoList) {
            return [
                'description' => $item['description'],
                'todo_list_id' => $todoList->id,
                'completed' => false, // Default to uncompleted (adjust if needed)
            ];
        });

        // Bulk insert items (more efficient than creating one-by-one)
        $todoList->items()->createMany($items);

        // Redirect back with success message
        return redirect()->back()->with('success', 'Todo list and items saved successfully!');
    }
}

4. Blade View Form

Build the form in your Blade template, with dynamic support to add more todo items using JavaScript (so users aren't limited to a fixed number of items).

<!DOCTYPE html>
<html>
<head>
    <title>Create New Todo List</title>
    <!-- Optional: Add Bootstrap for basic styling -->
    <style>
        .container { max-width: 600px; margin: 2rem auto; }
        .input-group { margin-bottom: 0.8rem; }
        .alert { margin-bottom: 1.5rem; }
    </style>
</head>
<body>
    <div class="container">
        <!-- Show success message if submission worked -->
        @if(session('success'))
            <div class="alert alert-success">
                {{ session('success') }}
            </div>
        @endif

        <form method="POST" action="{{ route('todo-lists.store') }}">
            @csrf

            <!-- Todo List Name Input -->
            <div class="mb-4">
                <label for="listName" class="form-label">Todo List Name</label>
                <input type="text" class="form-control @error('todo_list.name') border-red-500 @enderror"
                       id="listName" name="todo_list[name]"
                       value="{{ old('todo_list.name') }}" placeholder="e.g., 'Weekly Groceries'" required>
                @error('todo_list.name')
                    <p class="text-red-500 text-sm mt-1">{{ $message }}</p>
                @enderror
            </div>

            <!-- Todo Items Section -->
            <div class="mb-4">
                <label class="form-label">Todo Items</label>
                <div id="itemsContainer">
                    <!-- Initial todo item input -->
                    <div class="input-group">
                        <input type="text" class="form-control @error('items.0.description') border-red-500 @enderror"
                               name="items[0][description]"
                               value="{{ old('items.0.description') }}" placeholder="Add a todo item..." required>
                        @error('items.0.description')
                            <p class="text-red-500 text-sm mt-1">{{ $message }}</p>
                        @enderror
                    </div>
                </div>
                <button type="button" class="btn btn-outline-secondary mt-2" id="addItemBtn">Add Another Item</button>
            </div>

            <!-- Single Submit Button -->
            <button type="submit" class="btn btn-primary">Save Todo List & Items</button>
        </form>
    </div>

    <!-- JavaScript to add dynamic todo item inputs -->
    <script>
        document.getElementById('addItemBtn').addEventListener('click', function() {
            const container = document.getElementById('itemsContainer');
            const itemCount = container.children.length;

            // Create new input group
            const newItem = document.createElement('div');
            newItem.className = 'input-group mt-2';
            newItem.innerHTML = `
                <input type="text" class="form-control"
                       name="items[${itemCount}][description]"
                       placeholder="Add another todo item..." required>
            `;

            container.appendChild(newItem);
        });
    </script>
</body>
</html>

5. Route Setup

Don't forget to add the route in routes/web.php to point to your controller's store method:

use App\Http\Controllers\TodoListController;

Route::post('/todo-lists', [TodoListController::class, 'store'])->name('todo-lists.store');

Key Details to Note:

  • We use array input names (todo_list[name], items[][description]) to group related data, making it easy to handle in the controller.
  • Bulk inserting items with createMany is more efficient than looping and saving each item individually.
  • The JavaScript lets users add as many items as they need dynamically, and validation ensures at least one item is submitted.
  • Old form data is retained on validation failure, so users don't lose their input.

内容的提问来源于stack exchange,提问作者Jacobo de la Rosa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:49:16