2015-09-09 15 views
0

在我的symfony應用程序中,我以表格的形式渲染許多視圖。如何使用Symfony編輯表格的數據?

我很想編輯這些數據,方法是單擊表格單元格,填充新數據並動態保存。

我使用jEditable探討了jqGrid,DataTable,但都沒有提供簡單的方法來與jquery集成。

我已經結束了建立我自己的看法,用一個表格替換tr行,當點擊一個表格行但超級定製,現在我需要對其他元素使用相同的行爲,我感到有點灰心。

是否有Symfony最佳實踐?這是工作還是Angular還是React?我該怎麼辦 ?

我的夢想解決方案將會知道哪個實體字段正在編輯,編輯它並在返回結果之前驗證實體。

我的自定義代碼:

{% extends ':Template/Backend:backend.html.twig' %} 

{% block title_wrapper %} 
    <div class="row wrapper border-bottom white-bg page-heading"> 
     <div class="col-md-12 col-sm-12"> 
      <h2 class="inline-block">Coûts d'achat</h2> 
      <span id="header_buttons" class="pull-right"> 
       <a href="{{ path('user_supplier_select') }}" class="btn btn-sm btn-white">Ajouter un fournisseur</a> 
      </span> 
     </div> 
    </div> 
{% endblock %} 

{% block main %} 

    <p>Assignez des fournisseurs à vos ingrédients. Vous pourrez ensuite paramétrer le coût d'achat.</p> 
    <p>L'unité utilisée pour la quantité minimale d'achat est l'unité que vous utilisez pour gérer votre stock. Essayez d'adopter la même que votre fournisseur.</p> 


    {{ form_start(parameter_cost_form, {'attr' : {'id' : 'parameter_cost_form'}}) }} 
    {{ form_errors(parameter_cost_form) }} 
    {{ form_stylesheet(parameter_cost_form) }} 
    {{ form_javascript(parameter_cost_form) }} 


    <br> 
    <br> 
    <div class="table-responsive"> 
    <table class="DataTable table table-striped table-bordered table-hover" id="editable" > 
     <colgroup> 
      <col span="3"> 
      <col span="1" style="min-width: 80px !important"> 
     </colgroup> 
     <thead> 
     <tr> 
      <th>Ingrédient</th> 
      <th>Marque</th> 
      <th title="Quantité disponible dans un produit" data-toggle="tooltip" data-placement="top">Packaging</th> 
      <th title="Quantité payée qui divisera le prix pour obtenir le coût par unité" data-toggle="tooltip" data-placement="top">Quantité</th> 
      <th title="Unité utilisée pour calculer le coût de revient" data-toggle="tooltip" data-placement="top">Unité</th> 
      <th title="Montant payé pour la quantité donnée dans l'unité donnée" data-toggle="tooltip" data-placement="top">Montant HT (€)</th> 
      <th title="Quantité minimale d'achat en nombre de produits - permet d'arrondir les commandes à la quantité minimale servie par votre fournisseur" data-toggle="tooltip" data-placement="top">Q d'achat minimale</th> 
      <th>Fournisseur</th> 
      <th title="Référence qui sera indiquée dans les bons de commande" data-toggle="tooltip" data-placement="top">Référence fournisseur</th> 
      <th>Actions</th> 
     </tr> 
     </thead> 
     <tbody> 
      <tr id="edit_form" style="display: none;" class="child_collection"> 
       {# Data-repo and data-id are used for updating the unit fields #} 
       <td class="name" data-repo="AppBundle:FoodAnalytics\UserIngredient"></td> 
       <td class="brand"></td> 
       <td class="packaging"></td> 
       <td class="quantity"> 
        {{ form_widget(parameter_cost_form.quantity) }} 
        {{ form_errors(parameter_cost_form.quantity) }} 
       </td> 
       <td class="unit-control"> 
        {{ form_widget(parameter_cost_form.unit) }} 
        {{ form_errors(parameter_cost_form.unit) }} 
       </td> 
       <td class="numberObjects"> 
        {{ form_widget(parameter_cost_form.numberObjects) }} 
        {{ form_errors(parameter_cost_form.numberObjects) }} 
       </td> 
       <td class="minimumBuyingQuantity"> 
        {{form_widget(parameter_cost_form.minimumBuyingQuantity) }} 
        {{form_errors(parameter_cost_form.minimumBuyingQuantity) }} 
       </td> 
       <td class="userSupplier"> 
        {{ form_widget(parameter_cost_form.userSupplier) }} 
        {{ form_errors(parameter_cost_form.userSupplier) }} 
       </td> 
       <td class="supplierReference"> 
        {{ form_widget(parameter_cost_form.supplierReference) }} 
        {{ form_errors(parameter_cost_form.supplierReference) }} 
       </td> 
       <td class="action buttons"> 
        {{ form_widget(parameter_cost_form.submit) }} 
       </td> 
      </tr> 
     {% set i = 0 %} 
     {% for ingredient in user_ingredients %} 
      {% for uis in ingredient.userIngredientSuppliers %} 
       {% set i = i + 1 %} 
       <tr id="ingredient_{{ i }}" data-userIngredientId="{{ ingredient.id }}" data-userIngredientSupplierId="{{ uis.id }}" class="table_row"> 
        {# Data-repo and data-id are used for updating the unit fields #} 
        <td class="name" data-id="{{ ingredient.id }}">{{ ingredient.getProductName }}</td> 
        <td class="brand">{{ ingredient.getProductBrand }}</td> 
        <td class="packaging">{{ ingredient.getProductPackaging }}</td> 
        <td class="quantity">{{ uis.quantity }}</td> 
        <td class="unit-control" data-value="{{ uis.unit.id }}">{{ uis.unit }}</td> 
        <td class="numberObjects">{{ uis.getLastNumberObjectValue }}</td> 
        <td class="minimumBuyingQuantity">{{ uis.minimumBuyingQuantity }}</td> 
        <td class="userSupplier" data-value="{{ uis.userSupplier.id }}">{{ uis.userSupplier }}</td> 
        <td class="supplierReference">{{ uis.supplierReference }}</td> 
        <td class="action buttons"> 
         <a href="{{ path('user_ingredient_supplier_delete', {'userIngredientSupplier' : uis.id }) }}" class="btn btn-xs btn-white fmu_delete_button"><i class="fa fa-times"></i></a> 
         {#<a href="#/" class="btn btn-xs btn-white add"><i class="fa fa-plus"></i></a>#} 
        </td> 
       </tr> 
      {% else %} 
       {% set i = i + 1 %} 
       <tr id="ingredient_{{ i }}" data-userIngredientId="{{ ingredient.id }}" data-userIngredientSupplierId="" class="table_row empty"> 
        {# Data-repo and data-id are used for updating the unit fields #} 
        <td class="name" data-id="{{ ingredient.id }}">{{ ingredient.getProductName }}</td> 
        <td class="brand">{{ ingredient.getProductBrand }}</td> 
        <td class="packaging">{{ ingredient.getProductPackaging }}</td> 
        <td class="quantity"></td> 
        <td class="unit-control"></td> 
        <td class="numberObjects"></td> 
        <td class="minimumBuyingQuantity"></td> 
        <td class="userSupplier"></td> 
        <td class="supplierReference"></td> 
        <td class="action buttons"> 
         <a href="" class="btn btn-xs btn-white fmu_delete_button" style="display: none;"><i class="fa fa-times"></i></a> 
         {#<a href="#/" class="btn btn-xs btn-white add"><i class="fa fa-plus"></i></a>#} 
        </td> 
       </tr> 
      {% endfor %} 
     {% endfor %} 
     </tbody> 
     <tfoot> 
     <tr> 
      <th>Ingrédient</th> 
      <th>Marque</th> 
      <th>Packaging</th> 
      <th>Quantité</th> 
      <th>Unité</th> 
      <th>Montant HT (€)</th> 
      <th>Q d'achat minimale</th> 
      <th>Fournisseur</th> 
      <th>Référence fournisseur</th> 
      <th>Actions</th> 
     </tr> 
     </tfoot> 
    </table> 
    </div> 

    {{ form_end(parameter_cost_form) }} 

    {% import ':Model/Macros:_macros.html.twig' as macros %} 
    {{ macros.jqueryui_dialog('.fmu_delete_button', "Confirmation", 'Etes-vous sur de vouloir supprimer les informations de ce produit ?', 'Oui, supprimer', 'Non, annuler') }} 

    <script> 
     $(function(){ 

      var $editForm = $('#edit_form'); 
      var $parameterCostForm = $('#parameter_cost_form'); 

      $('#editable').on('click', 'td:not(:last-child)', function(){ 
       var $parent = $(this).parent(); 
       if ($parent.attr('id') == 'edit_form') { 
        return; 
       } 
       $($editForm.data('previous')).show(); 
       $editForm.insertAfter($parent); 
       $parent.hide(); 
       $editForm.data('previous', '#' + $parent.attr('id')); 
       $parameterCostForm.data('name', $parent.find('.name').eq(0).html()); 
       $editForm.find('.help-block').remove(); 
       $editForm.find('.form-control').attr('style', 'position:absolute !importante;'); 
       $editForm.show(); 

       $parameterCostForm.attr('action', '{{ path('parameter_cost') }}/' + $parent.attr('data-userIngredientId') + ($parent.attr('data-userIngredientSupplierId') ? '/' + $parent.attr('data-userIngredientSupplierId') : '')); 

       $editForm.find('.name').eq(0).attr('data-id', $parent.find('.name').eq(0).attr('data-id')); 
       $editForm.find('.name').eq(0).html($parent.find('.name').eq(0).html()); 
       $editForm.find('.brand').eq(0).html($parent.find('.brand').eq(0).html()); 
       $editForm.find('.packaging').eq(0).html($parent.find('.packaging').eq(0).html()); 
       $editForm.find('.quantity').eq(0).find('.form-control').val($parent.find('.quantity').eq(0).html()); 
       $editForm.find('.unit-control').eq(0).find('.form-control').val($parent.find('.unit-control').eq(0).attr('data-value')); 
       $editForm.find('.numberObjects').eq(0).find('.form-control').val($parent.find('.numberObjects').eq(0).html()); 
       $editForm.find('.minimumBuyingQuantity').eq(0).find('.form-control').val($parent.find('.minimumBuyingQuantity').eq(0).html()); 
       $editForm.find('.userSupplier').eq(0).find('.form-control').val($parent.find('.userSupplier').eq(0).attr('data-value')); 
       $editForm.find('.supplierReference').eq(0).find('.form-control').val($parent.find('.supplierReference').eq(0).html()); 
       $editForm.find('.name').eq(0).trigger('initiated'); 
      }); 

      {# Data-repo and data-id are used for updating the unit fields #} 
      var updateRow = function(){ 
       $editForm.find('.form-control').each(function(){ 
        var $previous = $($editForm.data('previous')); 
        var thisClass = $(this).closest('td').attr('class'); 
        var $eq = $previous.find('.' + thisClass).eq(0); 
        $previous.addClass('edited'); 

        if (thisClass == 'unit-control' || thisClass == 'userSupplier') { 
         $eq.html($(this).find('option:selected').text()); 
         $eq.attr('data-value', $(this).val()) 
        } else { 
         $eq.html($(this).val()); 
        } 
       }) 
      }; 

      $editForm.on('change', '.form-control', updateRow); 

      $('body').on('click', '#parameter_cost_form button[type="submit"]', function(e){ 
       e.preventDefault(); 
       $(this).attr('disabled', 'disabled'); 

       var formData = new FormData($parameterCostForm[0]); 

       console.log($parameterCostForm.attr('action')); 
       $editForm.data('sent', $editForm.data('previous')); 

       $.ajax({ 
        type  : 'post', 
        url   : $parameterCostForm.attr('action'), 
        data  : formData, 
        contentType: false, 
        cache: false, 
        processData: false 
       }).done(function(response){ 
        response = JSON.parse(response); 
        if ($editForm.data('previous') == $editForm.data('sent')) { 
         $editForm.find('td:nth-child(n+4)').remove(); 
         var $substitutes = $(response.view).find('td'); 
         $editForm.append($substitutes); 
         updateRow(); 

         if (response.success) { 

          var $previous = $($editForm.data('previous')); 
          if ($previous) { 
           $previous.attr('data-userIngredientSupplierId', response.id).removeClass('edited'); 
           $parameterCostForm.attr('action', response.action); 
           console.log(response.action); 
           var $action = $previous.find('.action a').eq(0); 
           if ($action.attr('href') == false) { 
            $action.attr('href', '{{ path('user_ingredient_supplier_delete') }}' + '/' + response.id); 
            $action.show(); 
           } 
          } 
          $.fn.logMessage('success', "L'ingrédient '" + $parameterCostForm.data('name') + "' a été enregistré."); 

         } else { 
          $.fn.logMessage('error', "L'ingrédient '" + $parameterCostForm.data('name') + "' n'a pas pu être enregistré. Vérifiez la validité des données renseignées."); 
          $editForm.find('.form-control').attr('style', 'position: relative !important;'); 
         } 

        } else { 
         var $sent = $($editForm.data('sent')); 
         $('#parameter_cost_form button[type="submit"]').removeAttr('disabled'); 
         if ($sent) { 
          if (response.success) { 
           $sent.removeClass('edited'); 
           $.fn.logMessage('success', "L'ingrédient '" + $sent.find('.name').eq(0).html() + "' a été enregistré."); 
          } else { 
           $.fn.logMessage('error', "L'ingrédient '" + $sent.find('.name').eq(0).html() + "' n'a pas pu être enregistré. Vérifiez la validité des données renseignées."); 
          } 
         } 
        } 

       }).fail(function(){ 
        $.fn.logMessage('error', "L'ingrédient '" + $parameterCostForm.data('name') + "' n'a pas pu être enregistré. Vérifiez la validité des données renseignées."); 
       }); 

      }) 
     }); 

    </script> 

    {{ macros.javascript_json_prefill('initiated', '#edit_form .name') }} 


    <style rel="stylesheet"> 
     .unit-control {min-width: 40px;} 
     #edit_form td:nth-child(n+4) { 
      padding: 0; 
      position: relative; 
     } 
     #edit_form .form-control, #edit_form .btn { 
      position: absolute; 
      top: 0; 
      left: 0; 
      right: 0; 
      bottom: 0; 
      height: 100%; 
      width:100%; 
      border: 0; 
     } 
     .edited { 
      background-color: #fffec9 !important; 
     } 
    </style> 

{% endblock %} 
+1

我後來開發了類似的東西,因爲我找不到任何有用的東西。我所做的是使用dom屬性創建從表單字段到列的映射。然後使用jquery我會用這些字段替換列的值,當一行上的特定按鈕被點擊後,然後使用另一個按鈕發送它們。這樣,您實際上可以使用您在處理其他地方使用的相同操作,並且你可以使用symfony表單。 – user2268997

+1

我剛剛閱讀了你已經完成的任務,爲了解決你正面臨的**多行**問題,將表單渲染到其他地方並隱藏它,並且每次單擊每行上的編輯按鈕時都會替換與表單字段在該行中的字段。 – user2268997

回答

2

我已經在幾個月前有完全相同的要求。我已經能夠成功整合free jqGrid與。

爲此,我使用了名爲thrace datagrid bundle的Symfony包。該軟件包可能有點棘手,但一旦計算出來,它使事情變得非常簡單。你提到的其他插件在性能(瀏覽器崩潰等)方面隨着行數的增加而惡化。而您可以修改修改jqGrid的樹枝,它的行爲將與您想要的一樣克服限制。

我從thrace datagrid包中獲取的所有數據是它返回的json數組。我已經能夠完全自定義前端,其中包括編輯數據,添加新數據,保存更改等操作,如等等。 我已經創建了超過30列的網格,它們工作得很好,因此應該回答您關於具有巨大視圖並且能夠編輯它們的顧慮。 jqGrid提供了各種你可以在前端本身提供的數據驗證。

我會建議給jqGrid(捆綁包)多一個Symfony鏡頭。我絕對可以幫助你整合jqGrid和Symfony。

+0

只有一個貢獻者,這並不令人放心...你是否能夠使用自己的symfony表單? –

+0

對不起,表單是什麼意思?如果您需要編輯/顯示數據,您可以創建實體,Thrace將負責其餘部分。 –

+0

好吧,symfony表單可以幫助您在發送數據之前驗證數據,它允許輕鬆構建選擇域等。我不知道thrace如何提供所有這些不錯的選項 –

相關問題