Bonjour,

J'ai des groupes de cases à cocher qui sont listées dans un tableau :

<table>
    <thead>
      <tr>
          <th>Groupe</th>
          <th>Positions</th>
      </tr>
    </thead>
    <tbody>
        /* Groupe 1 */
        <tr>
            <td>
                <input type="checkbox"  id="grp_1" name="grp_site_id[]" value="1" /> GRP1
             </td>
            <td>
                <input type="checkbox" id="position_1" name="position_id[]" value="1"> Voie 1<br />
                <input type="checkbox" id="position_2" name="position_id[]" value="2"> Voie 2<br />
                <input type="checkbox" id="position_3" name="position_id[]" value="3"> Voie 3
            </td>
        </tr>

        /* Groupe 2 */
        <tr>
            <td>
                <input type="checkbox"  id="grp_2" name="grp_site_id[]" value="2" /> GRP2
             </td>
            <td>
                <input type="checkbox" id="position_4" name="position_id[]" value="4"> Voie 4<br />
                <input type="checkbox" id="position_5" name="position_id[]" value="5"> Voie 5<br />
                <input type="checkbox" id="position_6" name="position_id[]" value="6"> Voie 6<br />
                <input type="checkbox" id="position_7" name="position_id[]" value="7"> Voie 7
            </td>
        </tr>

        /* Groupe 3 */
        Etc...
    </tbody>
</table>

Chaque ligne de mon tableau est générée à partir de ma base de données, je dois avoir en gros une dizaine de groupes.
Pour le traitement de mon formulaire, il serait idéal que les "names" de mes checkbox restent comme présentées ci-dessus.

Ce que je souhaiterais comme fonctionnement :

  • lorsque je coche la case du groupe toutes les voies du groupe se cochent
  • lorsque je décoche la case du groupe toutes les voies du groupe se décochent
  • lorsque je décoche une voie, si la case du groupe est cochée je la décoche
    avec bien sûr chaque groupe fonctionnement dépendamment.

J'ai trouvé des tonnes de solutions sur le net mais qui fonctionnent uniquement avec des groupes qui ne sont pas générés dynamiquement.

Je débute avec JS & jQuery et je ne sais pas par où commencer.

Si vous avez des conseils ou des idées de codes pour faire fonctionner ce petit formulaire je suis plus que preneur !

17 réponses


PLJerem
Auteur
Réponse acceptée

Ca y est, tout fonctionne.

J'ai mis l'écoute avec la fonction .on car mon < table > est appelé en AJAX.

Voilà le JS qui fonctionne :

jQuery(function($){
    var etat_parent;
    /* Si click sur la checkbox parent */
    $('#voie_container').on('click', '.parentCheckbox', function() {
        /* Si la parent est coché on met l'état à 1 */
        if($(this).is(':checked')) {
            etat_parent = 1;
        }
        /* Sinon on met l'état à 0 */
        else {
            etat_parent = 0;
        }

        /* Traitement sur les enfants */
        var inputChild = $(this).parent().next().children('input').each(function() {
            var kid = $(this);
            /* Si l'état du parent est à 1 on check tous les enfants */
            if(etat_parent==1)  {
                document.getElementById(kid.attr('id')).checked=true;
            }
            /* Sinon on décheck tous les enfants */
            else {
                document.getElementById(kid.attr('id')).checked=false;
            }
        });
    });

    /* Ecoute d'un click sur une des checkboxs enfant */
    $('#voie_container').on('click', '.childCheckbox', function() {
        /* Si l'enfant est décoché suite au click on décoche le parent */
        if($(this).is(':checked')==false)  {
            $(this).parent().prev().children('input').prop('checked', false);
        }
    });
})

Merci pour ta solution cattleyas10.

Bonsoir j'ai fait un truc rapide qui devrais fonctionner à tester :

<table>
            <thead>
              <tr>
                  <th>Groupe</th>
                  <th>Positions</th>
              </tr>
            </thead>
            <tbody>
                <tr>
                    <td>
                        <input type="checkbox"  id="grp_1" name="grp_site_id[]" value="1" onchange="cocheGroupe('grp_1');"/> GRP1
                     </td>
                    <td>
                        <input type="checkbox" id="position_1" name="position_id[]" value="1" onchange="decocheGrp('position_1');"> Voie 1<br />
                        <input type="checkbox" id="position_2" name="position_id[]" value="2" onchange="decocheGrp('position_2');"> Voie 2<br />
                        <input type="checkbox" id="position_3" name="position_id[]" value="3" onchange="decocheGrp('position_3');"> Voie 3
                    </td>
                </tr>

                <tr>
                    <td>
                        <input type="checkbox"  id="grp_2" name="grp_site_id[]" value="2" onchange="cocheGroupe('grp_2');"/> GRP2
                     </td>
                    <td>
                        <input type="checkbox" id="position_4" name="position_id[]" value="4" onchange="decocheGrp('position_4');"> Voie 4<br />
                        <input type="checkbox" id="position_5" name="position_id[]" value="5" onchange="decocheGrp('position_5');"> Voie 5<br />
                        <input type="checkbox" id="position_6" name="position_id[]" value="6" onchange="decocheGrp('position_6');"> Voie 6<br />
                        <input type="checkbox" id="position_7" name="position_id[]" value="7" onchange="decocheGrp('position_7');"> Voie 7
                    </td>
                </tr>

            </tbody>
        </table>
    </body>

et le js qui va avec :

<script type="text/javascript">
            var etat1;
            function decocheGrp(idCheckbox)
            {
                if($("#"+idCheckbox).is(':checked')==false)
                {
                    etat1 = 1;
                    console.log(etat1)
                }
                var inputGpr = $("#"+idCheckbox).parent().prev().children().each(function(){
                    var kid = $(this); 
                    if(etat1==1)
                    {
                        document.getElementById(kid.attr('id')).checked=false;
                    }//*/console.log(kid)
                });  
            }
            var etat;
            function cocheGroupe(idGroupe)
            {   
                if($('#'+idGroupe).is(':checked'))
                {
                    etat = 1;
                }
                else
                {
                    etat = 0;
                }
                     var parent = $("#"+idGroupe).parent().next().children('input').each(function(){
                        var kid = $(this);      
                        if(etat==1)
                        {
                            //on coche 
                            document.getElementById(kid.attr('id')).checked=true;
                         }
                        else
                        {
                            //on décoche tout
                            document.getElementById(kid.attr('id')).checked=false;
                        }
                    });     
            }
        </script>

Salut,

de mon coté j'aurai fais comme ça :

<!-- Groupe 1 -->
<tr>
    <td>
        <input type="checkbox"  id="grp_1" name="grp_site_id[]" value="1" /> GRP1
     </td>
    <td>
        <input type="checkbox" class="grp_1" id="position_1" name="position_id[]" value="1"> Voie 1<br />
        <input type="checkbox" class="grp_1" id="position_2" name="position_id[]" value="2"> Voie 2<br />
        <input type="checkbox" class="grp_1" id="position_3" name="position_id[]" value="3"> Voie 3
    </td>
</tr>

<!-- Groupe 2 -->
<tr>
    <td>
        <input type="checkbox"  id="grp_2" name="grp_site_id[]" value="2" /> GRP2
     </td>
    <td>
        <input type="checkbox" class="grp_2" id="position_4" name="position_id[]" value="4"> Voie 4<br />
        <input type="checkbox" class="grp_2" id="position_5" name="position_id[]" value="5"> Voie 5<br />
        <input type="checkbox" class="grp_2" id="position_6" name="position_id[]" value="6"> Voie 6<br />
        <input type="checkbox" class="grp_2" id="position_7" name="position_id[]" value="7"> Voie 7
    </td>
</tr>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>

<script type="text/javascript">

    var grp_1 = $( '#grp_1' );
    var grp_2 = $( '#grp_2' );

    var grp_1_items = $( '.grp_1' );
    var grp_2_items = $( '.grp_2' );

    grp_1.click(function() {
        if ($( this ).is(':checked')) {
            grp_1_items.prop('checked', true);
        }
        else {
            grp_1_items.prop('checked', false); 
        }
    });

    grp_2.click(function() {
        if ($( this ).is(':checked')) {
            grp_2_items.prop('checked', true);
        }
        else {
            grp_2_items.prop('checked', false); 
        }
    });

    grp_1_items.click(function() {
        if (!$( this ).is(':checked')) {
            grp_1.prop('checked', false);
        }
    });

    grp_2_items.click(function() {
        if (!$( this ).is(':checked')) {
            grp_2.prop('checked', false);
        }
    });

</script>

Je ne sais pas si c'est mieux ou moins bien.

[EDIT]
Prend plutôt la solution de cattleyas10,
il passe par des fonctions c'est bien mieux.
Et pas besoin de charger jQuery.

Bonjour.

Prend plutôt la solution de cattleyas10, il passe par des fonctions c'est bien mieux.
Et pas besoin de charger jQuery.

En fait si, même si ce n'est pas tout le temps, il utilise jQuery dans son exemple.

Ah zut xD

bah ça reste quand même mieux que mon code ^^

Effectivement je me sert quand même de Jquery , à savoir la meilleur solution je n'en ai aucune idée le souci avec ma solution c'est que je parcours les éléments du dom donc ca fonctionne bien si tu garde cette logique à savoir deux td un avec l'input group et un autre pour les voies

après ton code est pas mal aussi peut-être un mélange des deux genre ajouter la class="grp" au input group et la class="voies" au input voie et le js qui va avec

<script type="text/javascript">

             var etat;
            $('.grp').click(function() {

                if($(this).is(':checked'))
                {
                    etat = 1;
                }
                else
                {
                    etat = 0;
                }
                var parent = $(this).parent().next().children('input').each(function(){
                        var kid = $(this);      
                        if(etat==1)
                        {
                            //on coche 
                            document.getElementById(kid.attr('id')).checked=true;
                         }
                        else
                        {
                            //on décoche 
                            document.getElementById(kid.attr('id')).checked=false;
                        }
                    });   
            });

            var etat1;
            $('.voies').click(function() {
                if($(this).is(':checked')==false)
                {
                    etat1 = 1;
                }
                var inputGpr = $(this).parent().prev().children().each(function(){
                    var kid = $(this); 
                    if(etat1==1)
                    {
                        document.getElementById(kid.attr('id')).checked=false;
                    }/
                });  
            });
  </script>

ca fonctionne aussi et ca évite de surcharger le contenu des td une simple class à ajouter dans les différents input des td et plus de onchange ou onclick

PLJerem
Auteur

Salut,

Merci pour le temps passer.

J'ai effectué une petite modification pour pouvoir utiliser ton code dans tous les cas de figures où je peux en avoir besoin, pour les class j'ai défini comme suit :

  • parentCheckBox pour le groupe
  • childCheckBox pour les voies

Tu as laissé un petit "/" traîner à la fin après une "}" (4eme ligne en partant du bas).

Ca donne pour le JS :

<script type="text/javascript">
    var etat;
    /* Si click sur la checkbox parent */
    $('.parentCheckBox').click(function() {
        /* Si la parent est coché on met l'état à 1 */
        if($(this).is(':checked')) {
            etat = 1;
        }
        /* Sinon on met l'état à 0 */
        else {
            etat = 0;
        }

        /* Traitement sur les enfants */
        var parent = $(this).parent().next().children('input').each(function() {
            var kid = $(this);
            /* Si l'état du parent est à 1 on check tous les enfants */
            if(etat==1)  {
                document.getElementById(kid.attr('id')).checked=true;
            }
            /* Sinon on décheck tous les enfants */
            else {
                document.getElementById(kid.attr('id')).checked=false;
            }
        });
    });

    var etat1;
    /* Si click sur une des checkbox enfant */
    $('.childCheckBox').click(function()  {
        if($(this).is(':checked')==false)  {
            etat1 = 1;
        }

        /* Traitement sur le parent */
        var inputChild = $(this).parent().prev().children().each(function() {
            var kid = $(this);
            if(etat1==1)  {
                document.getElementById(kid.attr('id')).checked=false;
            }
        });
    });
</script>

Je me suis permis de le commenter un peu plus, ca m'aide à la compréhension.

Tout fonctionne bien lorsque :

  • je clique sur le parent : tous les enfants se cochent
  • je reclique sur la parent : tous les enfants sont décochés

Par contre si je déselectionne un des enfants ca ne me décoche pas le parent.

En mettant des alerts je sais que j'arrive bien dans le traitement du parent :

 if(etat1==1)  {
    document.getElementById(kid.attr('id')).checked=false;
 }

Je cherche voir d'où ca peut venir.

Je te donne quelques lignes de mon tableau pour voir si le problème provient de sa faute ou si le sélecteur n'arrive pas à cibler l'input parent :

<table>
    <thead>
    <tr>
        <th width="10%"><strong>Groupe</strong></th>
        <th width="10%"><strong>Toutes</strong></th>
        <th width="80%"><strong>Choix position</strong></th>
    </tr>
    </thead>
    <tbody>
    <tr>
        <td><strong>GRP1</strong></td>
        <td><input type="checkbox" name="emp_grp_id[]" id="emp_grp_id[]" value="4" class="parentCheckBox" /></td>
        <td>
            <input type="checkbox" name="position_id[]" id="for_position_15" value="15" class="childCheckBox" /><label for="for_position_15">10</label>
            <input type="checkbox" name="position_id[]" id="for_position_9" value="9" class="childCheckBox" /><label  for="for_position_9">7</label>
            <input type="checkbox" name="position_id[]" id="for_position_11" value="11" class="childCheckBox" /> <label for="for_position_11">8</label>
            <input type="checkbox" name="position_id[]" id="for_position_13" value="13" class="childCheckBox" /> <label for="for_position_13">9</label>
        </td>
    </tr>
    <tr>
        <td><strong>GRP2</strong></td>
        <td><input type="checkbox" name="emp_grp_id[]" id="emp_grp_id[]" value="5" class="parentCheckBox" /></td>
        <td>
            <input type="checkbox" name="position_id[]" id="for_position_3" value="3" class="childCheckBox" /> <label for="for_position_3">3</label>
            <input type="checkbox" name="position_id[]" id="for_position_4" value="4" class="childCheckBox" /> <label for="for_position_4">4</label>
            <input type="checkbox" name="position_id[]" id="for_position_5" value="5" class="childCheckBox" /> <label for="for_position_5">5</label>
            <input type="checkbox" name="position_id[]" id="for_position_7" value="7" class="childCheckBox" /> <label for="for_position_7">6</label>
        </td>
    </tr>
    <tr>
        <td><strong>GRP3</strong></td>
        <td><input type="checkbox" name="emp_grp_id[]" id="emp_grp_id[]" value="6" class="parentCheckBox" /></td>
        <td>
            <input type="checkbox" name="position_id[]" id="for_position_1" value="1" class="childCheckBox" /> <label for="for_position_1">1</label>
            <input type="checkbox" name="position_id[]" id="for_position_2" value="2" class="childCheckBox" /> <label for="for_position_2">2</label>
        </td>
    </tr>
    </tbody>
</table>

L'utilisation de la librairie jQuery ne me pose aucun problème, je l'utilise déjà pour quelques fonctions de mon portail.

PLJerem
Auteur

Je viens de faire quelques tests avec la console en mettant ca :

/* Traitement sur le parent */
        var inputChild = $(this).parent().prev().children().each(function() {
            var kid = $(this);
            if(etat1==1)  {
                console.log(kid);
                document.getElementById(kid.attr('id')).checked=false;
                console.log(kid);
            }
        });

Ce qui me donne dans la console du navigateur :

Object { 0: <input#emp_grp_id[].parentCheckBox>, context: <input#emp_grp_id[].parentCheckBox>, length: 1 } 
Object { 0: <input#emp_grp_id[].parentCheckBox>, context: <input#emp_grp_id[].parentCheckBox>, length: 1 }

Si je clique sur "<input#emp_grp_id[].parentCheckBox>" du context à chaque fois la valeur "checked : true"

Firefox m'indique bien dans l'inspecteur que le noeud correspond à la checkbox à décocher...

C'est étrange car je viens de teste ce que tu m'as donné et quand je décoche une voie ca décoche bien le groupe....

Essai de vider le cache de ton navigateur au cas ou^^

PLJerem
Auteur

Bon je confirme que ton code fonctionne. J'ai essayé en mettant le code juste dans une page à part de mon seveur et nickel.
En gros une page .html avec juste :

  • code du < table >
  • balise < script > pour insérer jQuery
  • ton code entre des balises < script >

Par contre dans le cadre de mon portail juste la fonction pour cocher / décocher les enfants fonctionne.
Je n'ai pas trop de doutes mais je pense que c'est mon modèle MVC qui doit poser problème.

Par exemple au début, en suivant les bonnes pratiques, j'avais placé la balise < script src=".../jquery.js" >< /script > juste avant mon < /body > mais pour des raisons que j'ignore certains de mes scripts JS ne fonctionnaient pas, j'ai dû placer l'appel dans le < header >.

Tous mes scripts sont placés dans des fichiers .js dans un répertoire : public/js/lefichier.js que j'appelle dans la vue que je souhaite afficher.

Je suis en train de tenter 2/3 trucs mais rien n'y fait...

ha oui ok je vois si tu le place dans un fichier et qu'il se trouve dans le head prend ceci plutôt :

jQuery(function($){
    var etat;
    /* Si click sur la checkbox parent */
    $('.parentCheckBox').click(function() {
        /* Si la parent est coché on met l'état à 1 */
        if($(this).is(':checked')) {
            etat = 1;
        }
        /* Sinon on met l'état à 0 */
        else {
            etat = 0;
        }

        /* Traitement sur les enfants */
        var parent = $(this).parent().next().children('input').each(function() {
            var kid = $(this);
            /* Si l'état du parent est à 1 on check tous les enfants */
            if(etat==1)  {
                document.getElementById(kid.attr('id')).checked=true;
            }
            /* Sinon on décheck tous les enfants */
            else {
                document.getElementById(kid.attr('id')).checked=false;
            }
        });
    });

    var etat1;
    /* Si click sur une des checkbox enfant */
    $('.childCheckBox').click(function()  {
        if($(this).is(':checked')==false)  {
            etat1 = 1;
        }

        /* Traitement sur le parent */
        var inputChild = $(this).parent().prev().children().each(function() {
            var kid = $(this);
            if(etat1==1)  {
                document.getElementById(kid.attr('id')).checked=false;
            }
        });
    });
})

il faut simplement

jQuery(function($){

au début et

})

à la fin et ca devrais fonctionner

PLJerem
Auteur

Tous mes scripts JS sont déjà encadrés dans ces balises.

Enfin pour être précis :

(function ($) {

})(jQuery);

Mais si j'ai bien compris le résultat final est identique.

effectivement c'est étrange :(

Coucou je t'en prie , on y a tous contribué ;)