0
votes

Garder la mise en évidence précédente avec jquery

J'ai créé un tableau simple pour montrer le problème que je rencontre. Lorsqu'une valeur est mise en surbrillance avec une case à cocher, et si la valeur existe dans la deuxième case à cocher, elle est toujours en surbrillance. C'est bon. mais lorsque je décoche la première ou la deuxième case à cocher, le surlignage est parti bien qu'il soit toujours dans la première case à cocher et toujours cliqué. Existe-t-il un moyen de conserver la surbrillance lorsque la deuxième case à cocher est désélectionnée? J'espère avoir été clair. voici mon jsfiddle si vous préférez: https://jsfiddle.net/6k5caw8h/19/ Merci.

Html:

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<input id="nextColor" type="color" value="#9ac99d">
<form id="form1" name="form1" method="post" action="">
  <label><input type="checkbox" name="SelectAll" class="all" />SelectAll</label>
  <label><input type="checkbox" name="x" class="selector" />x</label>
  <label><input type="checkbox" name="y" class="selector" />y</label>
</form>

<form id="form1" name="form1" method="post" action="">
  <label><input type="checkbox" name="SelectAll" class="all" />SelectAll</label>
  <label><input type="checkbox" name="x" class="selector" />x</label>
  <label><input type="checkbox" name="z" class="selector" />z</label>
</form>
<table class="tb">
  <tbody>
    <tr>
      <td>x</td>
      <td>y</td>
    </tr>
    <tr>
      <td>z</td>
      <td>x</td>
    </tr>
    <tr>
      <td>q</td>
      <td>a</td>
    </tr>
  </tbody>
</table>
table.tb {
  border: 1px solid #CCC;
  font-family: Arial, Helvetica, sans-serif;
  font-size: 12px;
  border-collapse: collapse;
  table-layout: fixed;
  margin-left: 200px;
}

.tb td {
  padding: 5px;
  margin: 5px;
  border: 1px solid #ccc;
}
$(document).ready(function() {
  $('.selector').each(function() {
    $(this).on('click', function(e) {
      check($(this).prop("checked") ? $("#nextColor").val() : '#fff', $(this).attr("name"));
    });
  });
  $('.all').each(function() {
    $(this).on('click', all);
  });

  function all(event) {
    if ($(this).is(':checked')) {
      let checked = $("input:checkbox:not(:checked)", $(this).parents('form')).not(this);
      checked.prop("checked", true);
      check($("#nextColor").val(), ...checked.map((i, e) => e.name).get());
    } else {
      let checked = $("input:checkbox(:checked)", $(this).parents('form')).not(this);
      checked.prop("checked", false);
      check('#fff', ...checked.map((i, e) => e.name).get());
    }
  }

  function check(color, ...elements) {
    $('td').each((i, td) => {
      if (elements.includes($(td).text())) $(td).css('background', color);
    });
  }
});


1 commentaires

Votre code HTML n'est pas valide. Je ne peux pas avoir d'ID en double sur un élément.


3 Réponses :


2
votes

Votre problème, où décocher les cases à cocher qui ciblent le même alphabet semble ignorer l'état des autres, vient de cette ligne problématique:

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input id="nextColor" type="color" value="#9ac99d">

<form id="form1" name="form1" method="post" action="">

  <label><input type="checkbox" name="SelectAll" class="all" />SelectAll</label>
  <label><input type="checkbox" name="x" class="selector" />x</label>
  <label><input type="checkbox" name="y" class="selector" />y</label>

</form>

<form id="form1" name="form1" method="post" action="">

  <label><input type="checkbox" name="SelectAll" class="all" />SelectAll</label>
  <label><input type="checkbox" name="x" class="selector" />x</label>
  <label><input type="checkbox" name="z" class="selector" />z</label>

</form>


<table class="tb">
  <tbody>
    <tr>
      <td>x</td>
      <td>y</td>
    </tr>
    <tr>
      <td>z</td>
      <td>x</td>
    </tr>
    <tr>
      <td>q</td>
      <td>a</td>
    </tr>
  </tbody>
</table>

Dans cette ligne, vous vérifiez simplement si le la case à cocher spécifique sur laquelle on clique est cochée, alors que vous devriez en fait vérifier toutes vos cases à cocher avec le même attribut name et voir si l'une d'entre elles est cochée.

Donc, ce que vous pouvez faire est simplement de parcourir tous les .selectors et de les filtrer par (1) la valeur de leur attribut name qui correspond à la case à cocher actuelle, et (2) s'ils sont vérifiés. Si l'un d'entre eux est coché, le premier argument passé dans check () doit être true:

table.tb {
  border: 1px solid #CCC;
  font-family: Arial, Helvetica, sans-serif;
  font-size: 12px;
  border-collapse: collapse;
  table-layout: fixed;
  margin-left: 200px;
}

.tb td {
  padding: 5px;
  margin: 5px;
  border: 1px solid #ccc;
}

Mise à jour: cela ne semble pas résoudre votre problème car all () appelle également une logique alambiquée. Tout ce dont vous avez besoin est de:

  1. Cochez l'écouteur d'événement click sur .selector à .change
  2. Utilisez simplement la case à cocher .all pour déclencher les modifications des cases à cocher .selector et déclencher manuellement l'événement change . Cela provoque le déclenchement de la logique individuelle sur toutes les cases à cocher uniques, sans avoir à dupliquer aucune logique:
$(document).ready(function() {

  $('.selector').on('change', function(e) {
    const $sameNameSelector = $('.selector[name="' + $(this).attr('name') + '"]');
    const isAnySameNameSelectorChecked = $sameNameSelector.filter(function() {
      return this.checked
    }).length;
    check(isAnySameNameSelectorChecked ? $("#nextColor").val() : '#fff', $(this).attr("name"));
  });
  $('.all').each(function() {
    $(this).on('click', all);
  });

  function all(event) {
    $(this).closest('form').find('.selector').prop('checked', this.checked).trigger('change');
  }

  function check(color, ...elements) {
    $('td').each((i, td) => {
      if (elements.includes($(td).text())) $(td).css('background', color);
    });
  }


});

Conseil de pro: vous n'avez pas besoin de faire $ ('. selector'). each ({$ (this) .on ('.. . ');}) puis liez le gestionnaire d'événements. jQuery peut gérer cela intelligemment, vous pouvez donc simplement faire `$ ('. selector'). on (...); '.

function all(event) {
    $(this).closest('form').find('.selector').prop('checked', this.checked).trigger('change');
}
const $sameNameSelector = $('.selector[name="'+$(this).attr('name')+'"]');
const isAnySameNameSelectorChecked = $sameNameSelector.filter(function() { return this.checked }).length;
check(isAnySameNameSelectorChecked ? $("#nextColor").val() : '#fff', $(this).attr("name"));
check($(this).prop("checked") ? $("#nextColor").val() : '#fff', $(this).attr("name"));


3 commentaires

@Max Désolé, j'ai accidentellement frappé Ctrl-Z lors de l'enregistrement qui a enregistré un changement. Cela devrait fonctionner maintenant (voir Mise à jour Fiddle Link).


@Max Je vois que ça marche: avez-vous vérifié le dernier violon? jsfiddle.net/teddyrised/pbvq5k4L/9 Votre problème initial est de vérifier deux X puis en décochant une, toutes les cellules avec 'x' ne sont pas surlignées, non?


@Max Ah, je vois que votre méthode all () a une logique vraiment compliquée. Je vais mettre à jour ma réponse à une seule ligne. Je vais déplacer l'extrait de code de jsfiddle vers ma réponse :)



1
votes

Pour conserver la mise en évidence précédente, vous devez conserver un historique des vérifications quelque part et la couleur qui a été sélectionnée lors de la vérification. Un moyen simple de le faire serait d'assigner les données de couleur et l'horodatage directement à la case à cocher. Le javascript suivant résout le problème réel de la gestion d'un historique de sorte que lorsque les vérifications sont supprimées, la couleur des vérifications précédentes est restaurée.

J'ai remanié le code pour faire une boucle de rendu renderChecks () qui est un modèle de conception plus facile à maintenir.

Voir: https://jsfiddle.net/c6pt0eb5/1/

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<input id="nextColor" type="color" value="#9ac99d">
<form id="form1" name="form1" method="post" action="">
  <label><input type="checkbox" name="SelectAll" class="all" />SelectAll</label>
  <label><input type="checkbox" name="x" class="selector" />x</label>
  <label><input type="checkbox" name="y" class="selector" />y</label>
</form>

<form id="form1" name="form1" method="post" action="">
  <label><input type="checkbox" name="SelectAll" class="all" />SelectAll</label>
  <label><input type="checkbox" name="x" class="selector" />x</label>
  <label><input type="checkbox" name="z" class="selector" />z</label>
</form>
<table class="tb">
  <tbody>
    <tr>
      <td>x</td>
      <td>y</td>
    </tr>
    <tr>
      <td>z</td>
      <td>x</td>
    </tr>
    <tr>
      <td>q</td>
      <td>a</td>
    </tr>
  </tbody>
</table>
table.tb {
  border: 1px solid #CCC;
  font-family: Arial, Helvetica, sans-serif;
  font-size: 12px;
  border-collapse: collapse;
  table-layout: fixed;
  margin-left: 200px;
}

.tb td {
  padding: 5px;
  margin: 5px;
  border: 1px solid #ccc;
}
$(document).ready(function() {

  $('.selector').each(function() {
    $(this).on('click', function(e) {
      if ($(this).is(':checked')) {
      	$(this).data("color",[$("#nextColor").val(),Date.now()]);
      }
      renderChecks();
    });
  });
  $('.all').each(function() {
    $(this).on('click', all);
  });

  function all(event) {
    if ($(this).is(':checked')) {
      let checked = $("input:checkbox", $(this).parents('form')).not(this);
      checked.prop("checked", true);
      checked.data("color",[$("#nextColor").val(),Date.now()]);
    } else {
      let checked = $("input:checkbox(:checked)", $(this).parents('form')).not(this);
      checked.prop("checked", false);      
    }
    renderChecks();
  }

  function renderChecks() {
    const checks = {};
    const names = [];
  	$(".selector:checked").each((i,val) => {
       
       if (checks[$(val).attr('name')]) {
          checks[$(val).attr('name')].push($(val).data('color'));           
          checks[$(val).attr('name')].sort((a,b) => a - b);
       } else {
          checks[$(val).attr('name')] = [$(val).data('color')];
          names.push($(val).attr('name'));
       }});
       
       $('td').each((i, td) => {
           $(td).css('background','#fff');
           const text = $(td).text();
           let t = null;
           names.forEach((name) => {               
               if (text.includes(name)) {
                   if (t == null || t < checks[name][0][1]) {
                      t = checks[name][0][1];
                      $(td).css('background', checks[name][0][0]);
                   }
               }
           });                      
       });       
       
  }

});


  

Remarque: La réponse acceptée ne conserve pas la mise en évidence précédente, elle conserve simplement la mise en évidence actuelle.


1 commentaires

Merci, Ralph. Je vais vérifier votre solution.



1
votes

Je note que "SelectAll" ne devient pas coché lorsque tous les enfants sont cochés - je suppose que vous souhaitez le faire "coché" lorsque tous les enfants sont cochés (une exigence commune) afin de décocher tous les enfants que vous n'avez pas à cocher et décocher SelectAll.

L'autre chose est que vous souhaitez garder les vérifications associées cochées c.-à-d. lorsque vous cochez "x" voulez-vous que les AUTRES "x" soient cochés? SI vous le faites, supprimez les commentaires de cette ligne dans le code que je présente ici et les noms similaires cocheront et décocheront la synchronisation:

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>

<input id="nextColor" type="color" value="#9ac99d">
<label><input id="keepcolor" type="checkbox" name="keepcolor" />Keep Color</label>
<label><input id="resetcolor" type="checkbox" name="resetcolor" />Reset Color</label>
<form id="form1" name="form1" method="post" action="">
  <label><input type="checkbox" name="SelectAll" class="all" />SelectAll</label>
  <label><input type="checkbox" name="x" class="selector" />x</label>
  <label><input type="checkbox" name="y" class="selector" />y</label>
</form>

<form id="form2" name="form2" method="post" action="">
  <label><input type="checkbox" name="SelectAll" class="all" />SelectAll</label>
  <label><input type="checkbox" name="x" class="selector" />x</label>
  <label><input type="checkbox" name="z" class="selector" />z</label>
</form>
<table class="tb">
  <tbody>
    <tr>
      <td>x</td>
      <td>y</td>
    </tr>
    <tr>
      <td>z</td>
      <td>x</td>
    </tr>
    <tr>
      <td>q</td>
      <td>a</td>
    </tr>
  </tbody>
</table>

OK, maintenant que nous avons dépassé la gestion des cases à cocher, Regardons garder le point culminant. Maintenant, cette exigence n'est pas claire - vous les mettez en blanc #fff lorsque vous décochez. Souhaitez-vous cela ou seulement lorsque TOUS ne sont pas cochés? Ou ne devenez jamais blanc; c'est-à-dire qu'une fois avec une couleur ils la conservent même si elle n'est pas cochée? Mon deuxième exemple a des moyens de garder la couleur en surbrillance lorsqu'elle n'est pas cochée et de réinitialiser également le choix de couleur actuel.

table.tb {
  border: 1px solid #CCC;
  font-family: Arial, Helvetica, sans-serif;
  font-size: 12px;
  border-collapse: collapse;
  table-layout: fixed;
  margin-left: 200px;
}

.tb td {
  padding: 5px;
  margin: 5px;
  border: 1px solid #ccc;
}
$(function() {
  let cbx = "[type='checkbox']";
  let cbxSel = ".selector" + cbx;
  $(cbxSel) //.add('.all[type="checkbox"]')
    .on('change', function(e) {
      let me = $(this);
      let myname = $(this).attr("name");
      let namesel = "[name='" + myname + "']";
      let allpeer = $(".all" + cbx);
      let namedPeers = $(cbxSel + namesel);
      let allChecksNotMe = namedPeers.not(me);
      let isChecked = this.checked;
      // uncomment to keep like checks in sync
      //  allChecksNotMe.prop("checked", isChecked);
      allpeer.trigger('allchecked');
      let anyNamedChecked = !!namedPeers.filter(":checked").length;
      let keep = $('#keepcolor')[0].checked;
      let reset = $('#resetcolor')[0].checked;
      check(anyNamedChecked, myname, keep, reset);
    });
  $('form').on('allchecked', '.all', function(event) {
    let myForm = $(event.delegateTarget);
    // checks on form
    let formChecks = myForm.find(cbxSel);
    let formChecksChecked = formChecks.filter(':checked');
    let areAllChecked = (formChecks.length == formChecksChecked.length);
    $(this).prop("checked", areAllChecked);
  })
  $('.all' + cbx).on('change', function() {
    let isChecked = this.checked;
    let myForm = $(this).closest('form');
    // checks on form
    myForm.find(cbxSel)
      .prop('checked', isChecked).trigger("change");
  });

  function check(anyNamedChecked, myname, keepColor = false, reset = true) {
    let color = $("#nextColor").val();
    let newColor = anyNamedChecked ? color : '#fff';
    let colorCSS = {
      'background-color': newColor
    };
    $('.tb tbody').find('td').filter(function(index) {
      return myname.includes($(this).text());
    }).each(function(index, element) {
      let me = $(element);
      if (keepColor) {
        let scolor = reset ? color : me.data("savecolor");
        if (!!scolor) {
          colorCSS = {
            'background-color': scolor
          };
        }
        me.data("savecolor", !!scolor ? scolor : color);
      }
      $(element).css(colorCSS);
    });
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<input id="nextColor" type="color" value="#9ac99d">
<form id="form1" name="form1" method="post" action="">
  <label><input type="checkbox" name="SelectAll" class="all" />SelectAll</label>
  <label><input type="checkbox" name="x" class="selector" />x</label>
  <label><input type="checkbox" name="y" class="selector" />y</label>
</form>

<form id="form2" name="form2" method="post" action="">
  <label><input type="checkbox" name="SelectAll" class="all" />SelectAll</label>
  <label><input type="checkbox" name="x" class="selector" />x</label>
  <label><input type="checkbox" name="z" class="selector" />z</label>
</form>
<table class="tb">
  <tbody>
    <tr>
      <td>x</td>
      <td>y</td>
    </tr>
    <tr>
      <td>z</td>
      <td>x</td>
    </tr>
    <tr>
      <td>q</td>
      <td>a</td>
    </tr>
  </tbody>
</table>

Alterner avec les différences de surbrillance:

table.tb {
  border: 1px solid #CCC;
  font-family: Arial, Helvetica, sans-serif;
  font-size: 12px;
  border-collapse: collapse;
  table-layout: fixed;
  margin-left: 200px;
}

.tb td {
  padding: 5px;
  margin: 5px;
  border: 1px solid #ccc;
}
$(function() {
  let cbx = "[type='checkbox']";
  let cbxSel = ".selector" + cbx;
  $(cbxSel) //.add('.all[type="checkbox"]')
    .on('change', function(e) {
      let me = $(this);
      let myname = $(this).attr("name");
      let namesel = "[name='" + myname + "']";
      let allpeer = $(".all" + cbx);
      let allChecksNotMe = $(cbxSel + namesel).not(me);
      let isChecked = this.checked;
      // uncomment to keep like checks in sync
      //  allChecksNotMe.prop("checked", isChecked);
      allpeer.trigger('checkcolor');
      let color = $("#nextColor").val();
      let newColor = isChecked ? color : '#fff';
      check(newColor, myname);
    });
  $('form').on('checkcolor', '.all', function(event) {
    let myForm = $(event.delegateTarget);
    // checks on form
    let formChecks = myForm.find(cbxSel);
    let formChecksChecked = formChecks.filter(':checked');
    let areAllChecked = (formChecks.length == formChecksChecked.length);
    $(this).prop("checked", areAllChecked);
  })
  $('.all' + cbx).on('change', function() {
    let isChecked = this.checked;
    let myForm = $(this).closest('form');
    // checks on form
    myForm.find(cbxSel)
      .prop('checked', isChecked).trigger("change");
  });

  function check(color, ...elements) {
    let newColor = {
      'background-color': color
    };
    $('.tb tbody').find('td').filter(function(index) {
      return elements.includes($(this).text());
    }).css(newColor);
  }
});
  //  allChecksNotMe.prop("checked", isChecked);


2 commentaires

Merci, Mark. c'est une autre excellente solution. En ce qui concerne vos questions, oui, je souhaite vérifier toutes les valeurs de cette ligne lorsque SelectAll est coché. Chaque SelectAll a un groupe de valeurs, et lorsqu'un SelectAll particulier est coché, seules les valeurs de ce groupe doivent être vérifiées (même s'il existe d'autres valeurs identiques). Et quand un SelectAll particulier n'est pas coché, toutes les valeurs de ce SelectAll deviennent blanches (pas de surbrillance). Même s'il est possible de cocher / décocher les valeurs une par une, je n'utilise que les vérifications SelectAll ici.


Votre réponse propose une autre manière de faire les deux. c'est vraiment une belle touche. Merci.