So I was developing a page with a table, where one could delete and edit the data on the table. Deleting was simple, it would do an AJAX request to delete, and then I’d remove the table row using jQuery.
But when you edit the row, you would also need to update the row after you did the edit. The table row was already defined in the twig template though, so couldn’t I just reuse it? Yes we can. This is probably rookie beginners stuff, but well, I’m still learning Symfony (and bootstrap, and basically all frontend stuff).
So, to illustrate, I had this piece of template in my page.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
<div class="paginationContainer" id="scheduledList"> {% block scheduleTable %} <table class="table table-striped table-condensed"> <thead> <tr> {# sorting of properties based on query components #} <th style="width: 20%">{{ knp_pagination_sortable(scheduledPagination, 'Sent at', 's.startDateTime') }}</th> <th style="width: 49%" {% if scheduledPagination.isSorted('s.topic') %} class="sorted"{% endif %}>{{ knp_pagination_sortable(scheduledPagination, 'Topic', 's.topic') }}</th> <th style="width: 10%">Status</th> <th style="width: 10%">PreProcess</th> <th style="width: 5%">Msgs</th> <th style="width: 2%"> </th> <th style="width: 2%"> </th> <th style="width: 2%"> </th> </tr> </thead> <tbody> {# table body #} {% for emailPromotionSchedule in scheduledPagination %} {% block scheduleRow %} <tr> <td>{{ emailPromotionSchedule.startDateTime|date('d-m-Y H:i:s') }}</td> <td>{{ emailPromotionSchedule.topic }}</td> <td>{{ emailPromotionSchedule.statusLabel }}</td> <td>{{ emailPromotionSchedule.preProcessAt is empty ? "" : emailPromotionSchedule.preProcessAt|date('d-m-Y H:i:s') }}</td> <td>{{ emailPromotionSchedule.numberOfMessages }}</td> <td><a href="{{ path('_promotion_est_members') }}?id={{ emailPromotionSchedule.emailPromotionScheduleId }}" class="icon icon-eye-open"> </a></td> <td> {% if ("now"|date('U') < (emailPromotionSchedule.preProcessAt|date('U')-600)) and not ((emailPromotionSchedule.status b-and 4) == 4) %} {# edit only for promotions aren't sent yet #} <a href="{{ path('_promotion_edit', {'id': emailPromotionSchedule.emailPromotionScheduleId }) }}" class="icon icon-edit"></a> {% endif %} </td> <td><a href="{{ path('_promotion_remove', { 'id': emailPromotionSchedule.emailPromotionScheduleId }) }}" class="icon icon-remove"> </a></td> </tr> {% endblock scheduleRow %} {% endfor %} </tbody> </table> {# display navigation #} <div class="navigation"> {{ knp_pagination_render(scheduledPagination) }} </div> {% endblock %} </div> |
With jQuery, I had an event handler on the paginationContainer, to catch the edit button. This would open up a modal where the record can be edited. After that, the save button was pressed, which I was also catching using jQuery.
So this javascript code looked like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
$("#editRecord").on('click', '.save-button', function(event) { event.preventDefault(); $("#editRecord").modal('hide'); var target = $("#saveSchedule").attr('action'); $.post(target, $("#saveSchedule").serialize(), function(data) { if (data.result == 'ok') { if (tableRow) { tableRow.replaceWith(data.newRow); delete tableRow; } } else { $("#errorMsgContent").html(data.error); $("#errorMsg").modal('show'); } }, "json") .fail(function() { $("#errorMsgContent").html('Error!'); $("#errorMsg").modal('show'); }); }); |
So the controller needed to just return the table row, as defined in the template at the beginning of the post. The code in the controller was like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
/** * Update schedule through ajax * @param $id * * @Route("/update/{id}", requirements={"id" = "\d+"}, name="_promotion_update") */ public function updateAction($id) { $em = $this->getDoctrine() ->getManager(); $emailPromo = $em ->getRepository('MbDbMVibesEmailBundle:EmailPromotionSchedule') ->find($id); if ($emailPromo->getPid() > 0) { return new Response( json_encode(array( 'result' => 'error', 'error' => 'Schedule is already being processed. Could not save update.' ) )); } $form = $this->createForm(new EmailPromotionScheduleType(), $emailPromo); $request = $this->getRequest(); if ($request->isMethod('POST')) { $form->bind($request); if ($emailPromo->getStartDateTime()->format('U') < time()) { return new Response( json_encode(array( 'result' => 'error', 'error' => 'Start datetime is in the past' ) )); } if ($form->isValid()) { $em = $this->getDoctrine()->getManager(); $em->persist($emailPromo); $em->flush(); $template = $this->get('twig') ->loadTemplate("MbMVibesEmailBundle:Promotion:list/scheduleTable.html.twig"); $newRow = $template->renderBlock('scheduleRow', array( 'emailPromotionSchedule' => $emailPromo, )); return new Response( json_encode(array( 'result' => 'ok', 'newRow' => $newRow ) )); } } return new Response( json_encode(array( 'result' => 'error', 'error' => 'Unable to save schedule' ) )); } |