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

如何在CakePHP3中使用AJAX实现编辑与删除功能?

Fixing AJAX Edit & Delete in CakePHP 3 for Health Visitors

Hey there! I see you're stuck getting AJAX-based edit/delete working in CakePHP 3—let's fix this step by step. I'll modify your existing controller, view, and add the necessary JavaScript to make this work without page reloads.

First: Fix Your Controller (HealthVisitorsController.php)

First off, you had a typo in your controller filename (helathvisitors.php should be HealthVisitorsController.php to follow CakePHP conventions). Let's update the Edit and Delete methods to handle AJAX requests properly:

// HealthVisitorsController.php
use Cake\Utility\Hash;
use Cake\Datasource\Exception\NotFoundException;

public function edit($id) {
    $visitorTable = $this->loadModel('HealthVisitors'); // Cleaner than direct TableRegistry call
    $visitor = $visitorTable->get($id);

    // Handle AJAX/POST/PUT requests
    if ($this->request->is(['post', 'put', 'ajax'])) {
        // Use CakePHP's proper request data handling
        $data = $this->request->getData();
        $visitor = $visitorTable->patchEntity($visitor, $data);

        if ($visitorTable->save($visitor)) {
            // Return JSON response for AJAX instead of redirect
            if ($this->request->is('ajax')) {
                $this->set([
                    'success' => true,
                    'message' => __('Details Updated of user ID: {0}.', $id),
                    '_serialize' => ['success', 'message']
                ]);
                return;
            }
            $this->Flash->success(__('Details Updated of user ID: {0}.', $id));
            return $this->redirect(['action' => 'index']);
        } else {
            $errors = Hash::flatten($visitor->getErrors());
            if ($this->request->is('ajax')) {
                $this->set([
                    'success' => false,
                    'message' => __('Something went wrong. Please try again.'),
                    'errors' => $errors,
                    '_serialize' => ['success', 'message', 'errors']
                ]);
                return;
            }
            $this->Flash->error(__('Something wrong. Please, try again!!!!'));
        }
    }

    // Pass visitor data to view
    $this->set(compact('visitor'));
    // Render without layout for AJAX requests
    if ($this->request->is('ajax')) {
        $this->viewBuilder()->setLayout('ajax');
    }
}

public function delete($id) {
    $this->request->allowMethod(['post', 'delete', 'ajax']); // Restrict methods for security
    $visitorTable = $this->loadModel('HealthVisitors');

    try {
        $visitor = $visitorTable->get($id);
        $visitorTable->delete($visitor);

        if ($this->request->is('ajax')) {
            $this->set([
                'success' => true,
                'message' => __('Details deleted successfully.'),
                '_serialize' => ['success', 'message']
            ]);
            return;
        }
        $this->Flash->success(__('Details deleted successfully.'));
    } catch (NotFoundException $e) {
        if ($this->request->is('ajax')) {
            $this->set([
                'success' => false,
                'message' => __('Visitor not found.'),
                '_serialize' => ['success', 'message']
            ]);
            return;
        }
        $this->Flash->error(__('Visitor not found.'));
    }

    return $this->redirect(['action' => 'index']);
}

Key Controller Changes:

  • Used loadModel() instead of TableRegistry for cleaner, convention-compliant code
  • Added support for AJAX requests by returning JSON responses (using CakePHP's _serialize for JSON views)
  • Handled validation errors explicitly for AJAX calls
  • Restricted HTTP methods for delete to prevent unauthorized requests
  • Fixed typo: getdata() → getData() (CakePHP uses camelCase)
  • Removed setAction('Index') which caused unwanted redirects for AJAX

Second: Update Your View (index.ctp)

We'll add unique identifiers to buttons, a modal for editing, and fix the table structure:

<!-- index.ctp -->
<div class="container">
    <h1>Health Visitors</h1>
    <?= $this->Flash->render() ?> <!-- Flash messages for non-AJAX requests -->

    <!-- Edit Modal -->
    <div id="editModal" class="modal fade" tabindex="-1" role="dialog">
        <div class="modal-dialog" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title">Edit Visitor</h5>
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                        <span aria-hidden="true">&times;</span>
                    </button>
                </div>
                <div id="editModalBody" class="modal-body">
                    <!-- AJAX will load the edit form here -->
                </div>
            </div>
        </div>
    </div>

    <table class="table table-striped">
        <thead>
            <tr>
                <td>ID</td>
                <td>Name</td>
                <td>Age</td>
                <td>Mobile</td>
                <td>Gender</td>
                <td>Insured</td>
                <td>Insured Child</td>
                <td>Pincode</td>
                <td>Action</td>
            </tr>
        </thead>
        <tbody>
            <?php foreach ($results as $row): ?>
            <tr id="visitor-row-<?= $row->id ?>">
                <td><?= $row->id ?></td>
                <td><?= $row->name ?></td>
                <td><?= $row->age ?></td>
                <td><?= $row->mobile ?></td>
                <td><?= $row->gender ?></td>
                <td><?= $row->insured ?></td>
                <td><?= $row->children ?></td>
                <td><?= $row->pincode ?></td>
                <td>
                    <!-- Unique data attributes for each button -->
                    <button class="btn btn-sm btn-primary edit-btn" data-id="<?= $row->id ?>">Edit</button>
                    <button class="btn btn-sm btn-danger delete-btn" data-id="<?= $row->id ?>">Delete</button>
                </td>
            </tr>
            <?php endforeach; ?>
        </tbody>
    </table>
</div>

<!-- Include jQuery and Bootstrap (adjust paths as needed) -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.bundle.min.js"></script>

<script>
$(document).ready(function() {
    // Get CSRF token required for CakePHP AJAX requests
    const csrfToken = $('meta[name="csrfToken"]').attr('content');

    // Handle Edit Button Click
    $('.edit-btn').click(function() {
        const visitorId = $(this).data('id');
        // Load edit form via AJAX
        $.ajax({
            url: '/health-visitors/edit/' + visitorId,
            type: 'GET',
            headers: {
                'X-CSRF-Token': csrfToken
            },
            success: function(response) {
                $('#editModalBody').html(response);
                $('#editModal').modal('show');
            },
            error: function() {
                alert('Failed to load edit form.');
            }
        });
    });

    // Handle Edit Form Submission
    $(document).on('submit', '#editVisitorForm', function(e) {
        e.preventDefault();
        const formData = $(this).serialize();
        const visitorId = $(this).data('id');

        $.ajax({
            url: '/health-visitors/edit/' + visitorId,
            type: 'PUT',
            data: formData,
            headers: {
                'X-CSRF-Token': csrfToken
            },
            dataType: 'json',
            success: function(response) {
                $('#editModal').modal('hide');
                if (response.success) {
                    alert(response.message);
                    location.reload(); // Optional: Replace with row-specific updates instead of full reload
                } else {
                    alert(response.message);
                }
            },
            error: function() {
                alert('Failed to update visitor.');
            }
        });
    });

    // Handle Delete Button Click
    $('.delete-btn').click(function() {
        const visitorId = $(this).data('id');
        if (confirm('Are you sure you want to delete this visitor?')) {
            $.ajax({
                url: '/health-visitors/delete/' + visitorId,
                type: 'DELETE',
                headers: {
                    'X-CSRF-Token': csrfToken
                },
                dataType: 'json',
                success: function(response) {
                    if (response.success) {
                        $('#visitor-row-' + visitorId).remove(); // Remove row from table
                        alert(response.message);
                    } else {
                        alert(response.message);
                    }
                },
                error: function() {
                    alert('Failed to delete visitor.');
                }
            });
        }
    });
});
</script>

Key View Changes:

  • Added a Bootstrap modal to display the edit form without page reload
  • Used unique data-id attributes instead of duplicate id values on buttons (critical for JS to target the correct row)
  • Added CSRF token handling (CakePHP blocks AJAX requests without this)
  • Added event listeners for edit/delete buttons and form submission

Third: Create an AJAX Edit Form (edit.ctp)

Create a separate edit.ctp file in src/Template/HealthVisitors/ to render just the form for the modal:

<!-- src/Template/HealthVisitors/edit.ctp -->
<?= $this->Form->create($visitor, [
    'id' => 'editVisitorForm',
    'data-id' => $visitor->id
]) ?>
<div class="form-group">
    <?= $this->Form->label('name', 'Name') ?>
    <?= $this->Form->control('name', ['class' => 'form-control', 'label' => false]) ?>
</div>
<div class="form-group">
    <?= $this->Form->label('age', 'Age') ?>
    <?= $this->Form->control('age', ['class' => 'form-control', 'label' => false]) ?>
</div>
<div class="form-group">
    <?= $this->Form->label('mobile', 'Mobile') ?>
    <?= $this->Form->control('mobile', ['class' => 'form-control', 'label' => false]) ?>
</div>
<div class="form-group">
    <?= $this->Form->label('gender', 'Gender') ?>
    <?= $this->Form->control('gender', ['type' => 'radio', 'options' => ['Male' => 'Male', 'Female' => 'Female'], 'label' => false]) ?>
</div>
<div class="form-group">
    <?= $this->Form->label('insured', 'Insured') ?>
    <?= $this->Form->control('insured', ['class' => 'form-control', 'label' => false]) ?>
</div>
<div class="form-group">
    <?= $this->Form->label('children', 'Insured Child') ?>
    <?= $this->Form->control('children', ['class' => 'form-control', 'label' => false]) ?>
</div>
<div class="form-group">
    <?= $this->Form->label('pincode', 'Pincode') ?>
    <?= $this->Form->control('pincode', ['class' => 'form-control', 'label' => false]) ?>
</div>
<div class="modal-footer">
    <?= $this->Form->button('Save Changes', ['class' => 'btn btn-primary']) ?>
    <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
</div>
<?= $this->Form->end() ?>

Quick Tips for Production:

  • Replace alert() calls with smoother toast/Flash message implementations (like CakePHP's built-in flash messages rendered via AJAX)
  • Instead of reloading the page after edit, update the table row's HTML directly with new data to improve user experience
  • Ensure your CakePHP layout includes the CSRF meta tag (auto-added in default layouts: <meta name="csrfToken" content="<?= $this->request->getAttribute('csrfToken') ?>">)

内容的提问来源于stack exchange,提问作者Mohan Panwar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 06:54:07