如何使用Symfony编辑表的数据?

时间:2015-09-09 20:13:20

标签: jquery angularjs symfony jqgrid reactjs

在我的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 个答案:

答案 0 :(得分:2)

几个月前,我有完全相同的要求。我已成功将free jqGridSymfony 2.7整合。

为此,我使用了一个名为thrace datagrid bundle的Symfony包。捆绑包可能有点棘手,但一旦想到它就会让事情变得非常简单。您提到的其他插件在性能(浏览器崩溃等)方面随着行数的增加而恶化。您可以修改用于修改jqGrid的树枝,它将按照您希望它克服 Symfony 限制的方式运行。

我从thrace数据网格包中获取的是它返回的json数组。我已经能够完全自定义前端,其中包括编辑数据,添加新数据,保存更改等操作。 我已经创建了超过30列的网格,它们工作正常,因此应该回答您关于拥有巨大视图并能够编辑它们的问题。 jqGrid提供了您可以在前端本身提供的所有类型的数据验证。

我建议用Symfony再给jqGrid(捆绑)一个镜头。我绝对可以帮助你整合jqGrid和Symfony。