11484 sujets

JavaScript, DOM et API Web HTML5

Bonjour,
Tout d'abord merci d'avance de votre aide ,
Pour le contexte, Mon projet est sur Symfony 4 et je voudrais cacher certains champs de mon formulaire imbriquer et les ré afficher en fonction des valeurs précédentes jusque la rien de bien compliquer je pourrais me débrouiller tout seul mais le soucis c'est que impossible d'accéder aux champs du formulaire imbriquer qui sont ajouter grâce au prototype je vous met mes deux type de formulaire ainsi que ma vue Twig
FormulaireType.php

public function buildForm(FormBuilderInterface $builder, array $options)
   {
       $builder
           ->add('formNom')
           ->add('formDescription')
           
           ->add('IdTraitement',EntityType::class,[
               'class'=> FormTraitement::class,
               'choice_label' =>'TraitementNom'
           ])
           ->add('formActive')
           ->add('detailChamps',CollectionType::class,[
               'attr'=> ['id' => 'Proto'],
               'entry_type'   => DetailChampType::class,
               'allow_add'    => true,
               'allow_delete' => true,
               'prototype' => true,
               'label' => false,
               'by_reference' => false,
               'block_name' =>'detailChamp'
           ])
           ->add('Enregistrer', SubmitType::class);
   }
 
   public function configureOptions(OptionsResolver $resolver)
   {
       $resolver->setDefaults([
           'data_class' => Formulaire::class,
 
       ]);
   }

DetailChampType.php

public function buildForm(FormBuilderInterface $builder, array $options)
   {
       $builder
            
       ->add('ChampForm',EntityType::class, [
           'class' => ChampsForm::class,
           'choice_label' => 'champNom',
           'empty_data' => null,
           'required'   => false,
       ])
           ->add('Display')
           ->add('Dependance',EntityType::class, [
               'class' => ChampsForm::class,
               'choice_label' => 'champNom',
               'empty_data' => null,
               'required'   => false,
               ])
               ->add('Dependance_value',EntityType::class, [
                   'class' => ValueChamp::class,
                   'choice_label' => 'value',
                   'empty_data' => null,
                   'required'   => false,
                   ])
               ->add('ChampOrder')
               ;
   }

Vue Twig

{% extends 'base.html.twig' %}
 
{% block title %}Hello FormulaireController!
{% endblock %}
 
{% block body %}
 
 
<div class="container" style="padding-top:5%">
    <div class="jumbotron ">
        <h1>
            Générateur de formulaire</h1>
        {{ form_start(Forms) }}
        {{ form_row(Forms.formNom) }}
        {{ form_row(Forms.formDescription) }}
        {{ form_row(Forms.IdTraitement) }}
        {{ form_row(Forms.formActive) }}
 
 
        {% block _formulaire_detailChamps_row %}
            <div class="detailChamps_row">
                {{ form_label(Forms) }}
                {{ form_errors(Forms) }}
            {{ form_widget(Forms) }}
            </div>
      {% endblock %}
            <a href="#" id="add_category" class="btn btn-success">Ajouter un champ</a>
 
 
            {{ form_end(Forms) }}
        </div>
    </div>

JS

 {# On charge la bibliothèque jQuery. Ici, je la prends depuis le CDN google
                       mais si vous l'avez en local, changez simplement l'adresse. #}
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
 
    {# Voici le script en question : #}
    <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 = $('#formulaire_detailChamps');
 
// 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) {
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, 'Champ 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 = $('<a href="#" class="btn btn-danger">Supprimer</a>');
 
// Ajout du lien
$prototype.append($deleteLink);
 
// Ajout du listener sur le clic du lien pour effectivement supprimer la catégorie
$deleteLink.click(function (e) {
$prototype.remove();
index--;
e.preventDefault(); // évite qu'un # apparaisse dans l'URL
return false;
});
}
});
    </script>
 
 
Salut,
Si personne ne te répond c'est que personne ne comprend la question. Essaye de décrire plus en détail ce que tu essayes de faire et ce qui ne fonctionne pas. De plus, ce serait mieux d'avoir le rendu HTML final plutôt que le template twig. Voire même un exemple sur https://codepen.io. Smiley cligne
Salut Ostara merci de ta reponse,
Voici le rendu html :


<html>
	<head>
		<meta charset="utf-8">
		<meta http-equiv="X-UA-Compatible" content="IE=edge">
		<title>Générateur de formulaire</title>
		<meta name="description" content="Sufee Admin - HTML5 Admin Template">
		<meta name="viewport" content="width=device-width, initial-scale=1">

		<link rel="apple-touch-icon" href="/apple-icon.png">
		<link rel="shortcut icon" href="/favicon.ico">

		<link rel="stylesheet" href="/vendors/bootstrap/dist/css/bootstrap.min.css">
		<link rel="stylesheet" href="/vendors/font-awesome/css/font-awesome.min.css">
		<link rel="stylesheet" href="/vendors/themify-icons/css/themify-icons.css">
		<link rel="stylesheet" href="/vendors/flag-icon-css/css/flag-icon.min.css">
		<link rel="stylesheet" href="/vendors/selectFX/css/cs-skin-elastic.css">
		<link rel="stylesheet" href="/vendors/jqvmap/dist/jqvmap.min.css">
		<link rel="stylesheet" href="https://bootswatch.com/4/litera/bootstrap.css">


		<link rel="stylesheet" href="/assets/css/style.css">

		<link href='https://fonts.googleapis.com/css?family=Open+Sans:400,600,700,800' rel='stylesheet' type='text/css'>

	</head>
	<title>
		Hello FormulaireController!
	</title>
	</html></head><body>
<aside id="left-panel" class="left-panel">
	<nav class="navbar navbar-expand-sm navbar-default">

		<div class="navbar-header">
			<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#main-menu" aria-controls="main-menu" aria-expanded="false" aria-label="Toggle navigation">
				<i class="fa fa-bars"></i>
			</button>
			<a class="navbar-brand" href="./"><img src="/images/logo.png" alt="Logo"></a>
			<a class="navbar-brand hidden" href="./"><img src="/images/logo2.png" alt="Logo"></a>
		</div>

		<div id="main-menu" class="main-menu collapse navbar-collapse">
			<ul class="nav navbar-nav">
				<li class="active">
					<a href="#">
						<i class="menu-icon fa fa-user"></i>
						NRenaud
					</a>
											<li class="nav-item">
							<a href="/deconnexion" class="nav-link">

								Déconnexion</a>

						</li>
									</li>
				<h3 class="menu-title">Générateur de formulaire</h3>
				<!-- /.menu-title -->
			</li>
			<li class="menu-item-has-children dropdown">
				<a href="/">
					<i class="menu-icon fa fa-circle"></i>Formulaire</a>

			</li>
			<li class="menu-item-has-children dropdown">
				<a href="/champs/form/">
					<i class="menu-icon fa fa-circle"></i>Champs formulaire</a>

			</li>
			<li class="menu-item-has-children dropdown">
				<a href="/detail_champ/">
					<i class="menu-icon fa fa-circle"></i>Detail Champ
				</a>
			</li>
			<li class="menu-item-has-children dropdown">
				<a href="/value/">
					<i class="menu-icon fa fa-circle"></i>Valeurs
				</a>
			</li>
			<li class="menu-item-has-children dropdown">
				<a href="/traitement/">
					<i class="menu-icon fa fa-circle"></i>Traitement
				</a>
			</li>
			<li class="menu-item-has-children dropdown">
				<a href="/template/">
					<i class="menu-icon fa fa-circle"></i>Template mail
				</a>
			</li>


		</div>
		<!-- /.navbar-collapse -->
	</nav>
</aside><!-- /#left-panel --></body></body></nav>

<div class="container" style="padding-top:5%">
	<div class="jumbotron ">
		<h1>
			Générateur de formulaire</h1>
		<form name="formulaire" method="post">
		<div class="form-group"><label for="formulaire_formNom" class="required">Form nom</label><input type="text" id="formulaire_formNom" name="formulaire[formNom]" required="required" maxlength="255" class="form-control" /></div>
		<div class="form-group"><label for="formulaire_formDescription" class="required">Form description</label><input type="text" id="formulaire_formDescription" name="formulaire[formDescription]" required="required" maxlength="255" class="form-control" /></div>
		<div class="form-group"><label class="required" for="formulaire_IdTraitement">Id traitement</label><select id="formulaire_IdTraitement" name="formulaire[IdTraitement]" class="form-control"><option value="1">Email Hotline</option></select></div>
		<div class="form-group"><div class="form-check">        <input type="checkbox" id="formulaire_formActive" name="formulaire[formActive]" class="form-check-input" value="1" />
        <label class="form-check-label" for="formulaire_formActive">Form active</label></div></div>


					<div class="detailChamps_row">
				<legend class="col-form-label required">Formulaire</legend>
				
			<div id="formulaire"><fieldset class="form-group"><div id="formulaire_detailChamps" id="Proto" data-prototype="&lt;fieldset class=&quot;form-group&quot;&gt;&lt;legend class=&quot;col-form-label required&quot;&gt;__name__label__&lt;/legend&gt;&lt;div id=&quot;formulaire_detailChamps___name__&quot;&gt;&lt;div class=&quot;form-group&quot;&gt;&lt;label class=&quot;&quot; for=&quot;formulaire_detailChamps___name___ChampForm&quot;&gt;Champ form&lt;/label&gt;&lt;select id=&quot;formulaire_detailChamps___name___ChampForm&quot; name=&quot;formulaire[detailChamps][__name__][ChampForm]&quot; class=&quot;form-control&quot;&gt;&lt;option value=&quot;&quot;&gt;&lt;/option&gt;&lt;option value=&quot;36&quot;&gt;Smartphone&lt;/option&gt;&lt;option value=&quot;39&quot;&gt;Marque&lt;/option&gt;&lt;option value=&quot;40&quot;&gt;modele&lt;/option&gt;&lt;option value=&quot;41&quot;&gt;operateur&lt;/option&gt;&lt;option value=&quot;42&quot;&gt;forfait&lt;/option&gt;&lt;option value=&quot;43&quot;&gt;attestation_superieur&lt;/option&gt;&lt;option value=&quot;44&quot;&gt;Test&lt;/option&gt;&lt;option value=&quot;45&quot;&gt;Voiture&lt;/option&gt;&lt;/select&gt;&lt;/div&gt;&lt;div class=&quot;form-group&quot;&gt;&lt;div class=&quot;form-check&quot;&gt;        &lt;input type=&quot;checkbox&quot; id=&quot;formulaire_detailChamps___name___Display&quot; name=&quot;formulaire[detailChamps][__name__][Display]&quot; class=&quot;form-check-input&quot; value=&quot;1&quot; /&gt;
        &lt;label class=&quot;form-check-label&quot; for=&quot;formulaire_detailChamps___name___Display&quot;&gt;Display&lt;/label&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;form-group&quot;&gt;&lt;label class=&quot;&quot; for=&quot;formulaire_detailChamps___name___Dependance&quot;&gt;Dependance&lt;/label&gt;&lt;select id=&quot;formulaire_detailChamps___name___Dependance&quot; name=&quot;formulaire[detailChamps][__name__][Dependance]&quot; class=&quot;__Hide__ form-control&quot;&gt;&lt;option value=&quot;&quot;&gt;&lt;/option&gt;&lt;option value=&quot;36&quot;&gt;Smartphone&lt;/option&gt;&lt;option value=&quot;39&quot;&gt;Marque&lt;/option&gt;&lt;option value=&quot;40&quot;&gt;modele&lt;/option&gt;&lt;option value=&quot;41&quot;&gt;operateur&lt;/option&gt;&lt;option value=&quot;42&quot;&gt;forfait&lt;/option&gt;&lt;option value=&quot;43&quot;&gt;attestation_superieur&lt;/option&gt;&lt;option value=&quot;44&quot;&gt;Test&lt;/option&gt;&lt;option value=&quot;45&quot;&gt;Voiture&lt;/option&gt;&lt;/select&gt;&lt;/div&gt;&lt;div class=&quot;form-group&quot;&gt;&lt;label class=&quot;&quot; for=&quot;formulaire_detailChamps___name___Dependance_value&quot;&gt;Dependance value&lt;/label&gt;&lt;select id=&quot;formulaire_detailChamps___name___Dependance_value&quot; name=&quot;formulaire[detailChamps][__name__][Dependance_value]&quot; class=&quot;form-control&quot;&gt;&lt;option value=&quot;&quot;&gt;&lt;/option&gt;&lt;option value=&quot;2&quot;&gt;Android&lt;/option&gt;&lt;option value=&quot;3&quot;&gt;BlackBerry OS&lt;/option&gt;&lt;option value=&quot;4&quot;&gt;IOS&lt;/option&gt;&lt;option value=&quot;5&quot;&gt;Huawei&lt;/option&gt;&lt;option value=&quot;6&quot;&gt;Iphone&lt;/option&gt;&lt;option value=&quot;7&quot;&gt;Samsung&lt;/option&gt;&lt;option value=&quot;8&quot;&gt;oui&lt;/option&gt;&lt;option value=&quot;9&quot;&gt;non&lt;/option&gt;&lt;option value=&quot;10&quot;&gt;Samsung&lt;/option&gt;&lt;option value=&quot;11&quot;&gt;Renault&lt;/option&gt;&lt;option value=&quot;12&quot;&gt;Peugeot&lt;/option&gt;&lt;option value=&quot;13&quot;&gt;Huawei P20&lt;/option&gt;&lt;option value=&quot;14&quot;&gt;Huawei P20 Pro&lt;/option&gt;&lt;option value=&quot;15&quot;&gt;Huawei P20 lite&lt;/option&gt;&lt;option value=&quot;16&quot;&gt;Huawei P9 lite&lt;/option&gt;&lt;option value=&quot;17&quot;&gt;Huawei P9 &lt;/option&gt;&lt;option value=&quot;18&quot;&gt;Huawei P9 Pro&lt;/option&gt;&lt;/select&gt;&lt;/div&gt;&lt;div class=&quot;form-group&quot;&gt;&lt;label for=&quot;formulaire_detailChamps___name___ChampOrder&quot; class=&quot;required&quot;&gt;Champ order&lt;/label&gt;&lt;input type=&quot;number&quot; id=&quot;formulaire_detailChamps___name___ChampOrder&quot; name=&quot;formulaire[detailChamps][__name__][ChampOrder]&quot; required=&quot;required&quot; class=&quot;form-control&quot; /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/fieldset&gt;"></div></fieldset><div class="form-group"><button type="submit" id="formulaire_Enregistrer" name="formulaire[Enregistrer]" class="btn-primary btn">Enregistrer</button></div><input type="hidden" id="formulaire__token" name="formulaire[_token]" value="RLIPVHW-Y2x5NYlBARKofl8u9xhsNCJ9Im-vXgnwYC4" /></div>
			</div>
      			<a href="#" id="add_category" class="btn btn-success">Ajouter un champ</a>


			</form>
		</div>
	</div>
		<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

		<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 = $('#formulaire_detailChamps');

// 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) {
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, 'Champ 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 = $('<a href="#" class="btn btn-danger">Supprimer</a>');

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

// Ajout du listener sur le clic du lien pour effectivement supprimer la catégorie
$deleteLink.click(function (e) {
$prototype.remove();
index--;
e.preventDefault(); // évite qu'un # apparaisse dans l'URL
return false;
});
}
});
	</script>



</body></html>


En fait ce que je souhaite faire c'est juste cacher un élément du formulaire imbriquer de symfony que l'on peut voir sur cette capture upload/1596612997-77812-forum.png
Mon problème est que pour les cacher et les afficher il faut cibler une div et ou une class et impossible de cibler quoi que ce soit dans ce bout de formulaire (ce formulaire est ajouter dynamiquement par du JS avec un data-prototype)
Voila j’espère avoir été un peu plus clair et encore merci d'avance pour votre aide
Modérateur
Hello,
Pas certain que l'HTML corresponde au rendu du code plus haut… Pas grave, tu veux masquer mais que ça reste dans le DOM ou supprimer la génération ?
Si c'est supprimé, je pense qu'on voit clairement l'endroit où c'est défini dans DetailChampType.php
Si c'est le masqué, tu peux simplement englobé ton prototype lors de l'insert ($container.append($prototype);) dans un div et lui donner une class pour masquer cette partie…
Tu m'étonnes que tu ne comprennes rien ! Smiley lol


<div id="formulaire_detailChamps" id="Proto" data-prototype="">
    <fieldset class="form-group">
        <legend class="col-form-label required">__name__label__</legend>
        <div id="formulaire_detailChamps___name__">
            <div class="form-group">
                <label class="" for="formulaire_detailChamps___name___ChampForm">
                    Champ form
                </label>
                <select id="formulaire_detailChamps___name___ChampForm" 
                    name="formulaire[detailChamps][__name__][ChampForm]" 
                    class="form-control">
                    <option value=""></option>
                    <option value="36">Smartphone</option>
                    <option value="39">Marque</option>
                    <option value="40">modele</option>
                    <option value="41">operateur</option>
                    <option value="42">forfait</option>
                    <option value="43">attestation_superieur</option>
                    <option value="44">Test</option>
                    <option value="45">Voiture</option>
                </select>
            </div>
            ...
        </div>
    </fieldset>
</div>


Tu génères ton composant à partir d'un div vide, en prenant le code dans un attribut HTML. Tu pourrais mettre directement le HTML dans un div caché. On y verrait plus clair.

Je penses que ta méthode pour générer les formulaires n'est pas correcte, car tout l'intérieur du prototype est illisible. A partir du moment où un élément est créé par jquery avec $(template), il est ajouté au DOM et peut donc être ciblé par un sélecteur. Le problème est qu'ici, le code HTML est échappé, donc jQuery ne peut pas l'interpréter, à mon avis. Ton code d'ajout fonctionne ?

Tu parles de cacher un élément. Tu veux dire le bloc "dependance" par exemple ? Si c'est ça, tu génères toi même les id, donc il suffit de cibler l'id qui t'intéresse. Peux-tu décrire un exemple de fonctionnement ?

Ensuite tu te bases sur le nombre d'inputs pour calculer le nombre de composants présents. Comme ton composant contient 2 inputs, l'index initial vaudra 2 et non 1. Le caclul des noms et labels devrait être indépendant des composants graphiques. Par exemple en stockant l'id dans une variable ou un attribut HTML.

Pour ajouter le lien de suppression, tu listes les enfant du container. Seulement le premier élément de ton prototype est un fieldset et non un div.

Je te laisses tranquille avec le code JS pour le moment, mais tu pourrais au moins l'indenter correctement. Smiley cligne
Modifié par Ostara (05 Aug 2020 - 17:20)
Merci à vous deux mais j'ai réussi à faire ce que je voulais. Alors comment j'ai fais je ne sais pas du tout, j'ai réessayer normalement et tout marcher
Merci quand même