Symfony:使用自定义原型进行渲染收集

时间:2017-07-09 09:32:28

标签: symfony twig

情况:我有一个实体CompetenceGroupe(具有属性“titre”和“compe_items”)和一个实体“CompetenceItem”(具有属性“libelle”和“niveau”)。 CompetenceGroupe可以有多个CompetenceItem,因此它是一个集合。

为此,我创建了自己的原型来自定义集合的渲染。它运行正常,但是当我想编辑现有的CompetenceGroupe时,我遇到了问题,因为孩子的CompetenceItem没有在表单中呈现。

我告诉你我的代码。

CompetenceGroupeType

class CompetenceItemType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('libelle')
            ->add('niveau', EntityType::class, array(
                'class' => 'AppBundle:CompetenceNiveau',
                'choice_label' => 'libelle_competence_niveau_fr',
                'required' => false,
            ))
            ;
    }

    /**
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'AppBundle\Entity\CompetenceItem',
        ));
    }
}

CompetenceItemType

{{ form_start(formAddCompetence, { 'attr': {'class': 'formCompetenceAdd'} }) }}

    <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
        <h4 class="modal-title" id="myModalLabel">{{ libelleCategorie }}</h4>
    </div>

    <div class="modal-body">

        {{ dump(formAddCompetence) }}

        <h4><span class="label label-default">Les champs marqués d'un astérisque sont obligatoires.</span></h4>

        {# render the task's only field: description #}
        {{ form_row(formAddCompetence.titre) }}

        <div id="competence_groupe_competence_items"
             data-prototype="
             {% filter escape %}
                 {{ include('espaceUtilisateur/forms/prototypes/competence_item_prototype.html.twig', { 'item': formAddCompetence.competence_items.vars.prototype }) }}
             {% endfilter %}">

        </div>

        {{ form_widget(formAddCompetence._token) }}

        <br>
        <a href="#" id="add_category" class="btn btn-default">Ajouter une catégorie</a>

    </div>

    <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">Annuler</button>

        {% if objectCompetence.idCompetenceGroupe is not empty %}
            {{ form_widget(formAddCompetence.edit) }}
            <input type="hidden" name="idCompetenceGroupe" id="idCompetenceGroupe" value="{{ objectCompetence.idCompetenceGroupe }}">
        {% else %}
            {{ form_widget(formAddCompetence.save) }}
        {% endif %}
    </div>

<script type="text/javascript">
    $(document).ready(function() {
        // On récupère la balise <div> en question qui contient l'attribut « data-prototype » qui nous intéresse.
        var $container = $('div#competence_groupe_competence_items');

        // On définit un compteur unique pour nommer les champs qu'on va ajouter dynamiquement
        var index = $container.find(':input').length;

        // On ajoute un nouveau champ à chaque clic sur le lien d'ajout.
        $('#add_category').click(function(e) {
            addCategory($container);

            e.preventDefault(); // évite qu'un # apparaisse dans l'URL
            return false;
        });

        // On ajoute un premier champ automatiquement s'il n'en existe pas déjà un (cas d'une nouvelle annonce par exemple).
        if (index == 0) {
            //console.log('index');
            addCategory($container);
        } else {
            // S'il existe déjà des catégories, on ajoute un lien de suppression pour chacune d'entre elles
            $container.children('div').each(function() {
                addDeleteLink($(this));
            });
        }

        // La fonction qui ajoute un formulaire CategoryType
        function addCategory($container) {
            // Dans le contenu de l'attribut « data-prototype », on remplace :
            // - le texte "__name__label__" qu'il contient par le label du champ
            // - le texte "__name__" qu'il contient par le numéro du champ
            var template = $container.attr('data-prototype')
                            .replace(/__name__label__/g, 'Catégorie n°' + (index+1))
                            .replace(/__name__/g,        index)
                    ;


            // On crée un objet jquery qui contient ce template
            var $prototype = $(template);

            // On ajoute au prototype un lien pour pouvoir supprimer la catégorie
            addDeleteLink($prototype);

            // On ajoute le prototype modifié à la fin de la balise <div>
            $container.append($prototype);

            // Enfin, on incrémente le compteur pour que le prochain ajout se fasse avec un autre numéro
            index++;
        }

        // La fonction qui ajoute un lien de suppression d'une catégorie
        function addDeleteLink($prototype) {

            // Création du lien
            var $deleteLink = $('<div><a href="#" class="btn btn-danger">Supprimero</a></div>');

            // Ajout du lien
            $prototype.last().append($deleteLink);

            // Ajout du listener sur le clic du lien pour effectivement supprimer la catégorie
            $deleteLink.click(function(e) {
                $prototype.remove();

                e.preventDefault(); // évite qu'un # apparaisse dans l'URL
                return false;
            });
        }
    });
</script>

CompetenceGroupe的表单

<div class="form-group">
    {{ form_label(item.libelle, "libelle a", {'label_attr': {'class': 'col-md-3 control-label'}}) }}
    {{ form_errors(item.libelle) }}
    <div>
        {{ form_widget(item.libelle) }}
    </div>
</div>

<div class="form-group">
    {{ form_label(item.niveau, "niveau a", {'label_attr': {'class': 'col-md-3 control-label'}}) }}
    {{ form_errors(item.niveau) }}
    <div>
        {{ form_widget(item.niveau) }}
    </div>
</div>

我的自定义原型

{
  "name": "yarnTest",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "devDependencies": {
    "@types/express": "^4.0.36",
    "bootstrap-sass": "^3.3.7",
    "nodemon": "^1.11.0",
    "typescript": "^2.4.1"
  },
  "dependencies": {
    "@types/chalk": "^0.4.31",
    "chalk": "^2.0.1",
    "express": "^4.15.3",
    "ts-node": "^3.2.0"
  },
  "scripts": {
    "dev": "nodemon --exec 'ts-node --cache-directory .tscache' ./src/www.ts",
    "start": "ts-node --fast ./dist/www.ts"
  }
}

也许我的问题是缺少CompetenceGroupe的现有CompetenceItem的渲染。也许我必须循环才能渲染它们......正如你所看到的,我迷失了......

提前感谢您的建议!

1 个答案:

答案 0 :(得分:1)

你这样做的方式看起来非常错误,所以我认为没有人会花费数小时的时间来找到解决问题的棘手方法。您应该使用form theme而不是自己创建原型。

1)在CompetenceGroupeType.php中,添加以下方法:

public function getBlockPrefix()
{
    return 'competence_group';
}

2)在compe_item_prototype.html.twig中包装代码:

{% block competence_group_widget %}

    <div class="form-group">
        (...)
    </div>

{% endblock %}

同时将item替换为form

3)在您的视图中,在调用{{ form_start(formAddCompetence, {...} }) }}函数之前,添加以下内容:

{% form_theme formAddCompetence 'espaceUtilisateur/forms/prototypes/competence_item_prototype.html.twig' %}

我创建的插件有点垃圾邮件,但出于正确的目的:)你可以查看https://symfony-collection.fuz.org,它提供了很多关于如何创建表单集的示例。