如何在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 ofTableRegistryfor cleaner, convention-compliant code - Added support for AJAX requests by returning JSON responses (using CakePHP's
_serializefor JSON views) - Handled validation errors explicitly for AJAX calls
- Restricted HTTP methods for
deleteto 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">×</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-idattributes instead of duplicateidvalues 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
相关产品推荐
相关产品推荐

