Tableau avec case à cocher et action à la coche ou décoche

Bonjour,

J’ai réalisé un tableau de case à cocher comme suit sur le dashboard dans jeedom avec le plugin htmldisplay.
image

Le code est celui la :

<table id="planningTable" border="1">
  <tbody>
    <tr data-row-name="row1">
      <td><input type="checkbox" name="checkbox1"></td>
      <td><input type="checkbox" name="checkbox2"></td>
      <td><input type="checkbox" name="checkbox3"></td>
      <td><input type="checkbox" name="checkbox4"></td>
      <td><input type="checkbox" name="checkbox5"></td>
      <td><input type="checkbox" name="checkbox6"></td>
    </tr>
    <tr data-row-name="row2">
      <td><input type="checkbox" name="checkbox7"></td>
      <td><input type="checkbox" name="checkbox8"></td>
      <td><input type="checkbox" name="checkbox9"></td>
      <td><input type="checkbox" name="checkbox10"></td>
      <td><input type="checkbox" name="checkbox11"></td>
      <td><input type="checkbox" name="checkbox12"></td>
    </tr>
    <tr data-row-name="row3">
      <td><input type="checkbox" name="checkbox13"></td>
      <td><input type="checkbox" name="checkbox14"></td>
      <td><input type="checkbox" name="checkbox15"></td>
      <td><input type="checkbox" name="checkbox16"></td>
      <td><input type="checkbox" name="checkbox17"></td>
      <td><input type="checkbox" name="checkbox18"></td>
    </tr>
    <tr data-row-name="row4">
      <td><input type="checkbox" name="checkbox19"></td>
      <td><input type="checkbox" name="checkbox20"></td>
      <td><input type="checkbox" name="checkbox21"></td>
      <td><input type="checkbox" name="checkbox22"></td>
      <td><input type="checkbox" name="checkbox23"></td>
      <td><input type="checkbox" name="checkbox24"></td>
    </tr>
    <tr data-row-name="row5">
      <td><input type="checkbox" name="checkbox25"></td>
      <td><input type="checkbox" name="checkbox26"></td>
      <td><input type="checkbox" name="checkbox27"></td>
      <td><input type="checkbox" name="checkbox28"></td>
      <td><input type="checkbox" name="checkbox29"></td>
      <td><input type="checkbox" name="checkbox30"></td>
    </tr>
    <tr data-row-name="row6">
      <td><input type="checkbox" name="checkbox31"></td>
      <td><input type="checkbox" name="checkbox32"></td>
      <td><input type="checkbox" name="checkbox33"></td>
      <td><input type="checkbox" name="checkbox34"></td>
      <td><input type="checkbox" name="checkbox35"></td>
      <td><input type="checkbox" name="checkbox36"></td>
    </tr>
    <tr data-row-name="row7">
      <td><input type="checkbox" name="checkbox37"></td>
      <td><input type="checkbox" name="checkbox38"></td>
      <td><input type="checkbox" name="checkbox39"></td>
      <td><input type="checkbox" name="checkbox40"></td>
      <td><input type="checkbox" name="checkbox41"></td>
      <td><input type="checkbox" name="checkbox42"></td>
    </tr>
  </tbody>
</table>

Je souhaiterai maintenant « lire » les valeurs des cases à cocher via un scénario (coché, ou pas coché) afin de déclencher des actions. Est-ce possible ?

Merci !

Bonjour
Ce serai peut être plus simple en mettant des virtuel de ce type
image
à la place des case à cocher et lancer les scénario en fonction de l’état des virtuels
Damien

1 « J'aime »

Bonjour.

Exemple :

Édit : après avoir vu votre réponse, notre proposition ne correspond pas du tout.

Oui, je pense que c’est en effet plus simple en passant par les virtuels.
Si vraiment tu veux des cases à cochées pour lesquelles tu choisis le look et tout puisque tu écris toi même le html, le seul moyen qui me vient en tête est de faire des appels Ajax vers un script php dédié qui se chargera de faire le lien entre tes cases à cocher et des commandes information d’un virtuel associé (ou des variables, mais dans ton cas je choisirais un virtuel).

Tu peux t’inspirer de ce sujet :

1 « J'aime »

Ce qui me faisait m’orienter vers des cases à cocher était dans le fait que j’étais sur un tableau avec de nombreuses cases (42). La création d’un virtuel entraine la création de deux commandes et d’une info ce qui fait en tout 126 éléments à créer dans le virtuel… ca va devenir compliqué niveau nommage et suivi :frowning:

L’objectif n’est pas de travailler le look, mais de rendre la lecture et la modification rapides ! Je vais voir ce que je peux faire :slight_smile: Je tiendrais ce fil au fur et à mesure si je trouve ce qui me convient :slight_smile: Merci !

Pas du tout tu peux uniquement faire avec des commandes info si tu pousse toi même la valeur a ces dernières.

Hum, merci à tous. @Aurel, je ne suis pas certain d’avoir compris ta proposition.
J’explique mon besoin clairement.
J’aimerai sur le dashboard un truc comme ca
image
Je pourrais comme ca désactiver / activer le créneau par exemple du lundi 10h juste en décochant / cochant la case.
Ensuite, un scénario viendrait lire le tableau, et dirait : nous sommes lundi, je dois faire l’action à 8h, 10h et 14h (dans l’exemple, ce sont les cases cochées).
Est-ce plus clair ?
Avec les propositions de @TonioBDS, @Dams et @Fabrice de passer par un virtuel, de ce que j’en connais il faut une action on, une off, et une info liée non ?

Je n’avais pas tellement d’avis sur le sujet, je répondais juste à « La création d’un virtuel entraine la création de deux commandes et d’une info ce qui fait en tout 126 éléments à créer dans le virtuel… »

Tu peux très bien n’avoir que des commandes info si tu as un moyen de les mettre à jour directement sans passer par une commande (par du code, un scénario …).

Mais c’est bien d’avoir expliqué ce que tu veux faire en détail ça permet à tout le monde de s’y retrouver :slight_smile:

Honnêtement la je sais pas faire ce que tu veux …

Merci @Aurel ! Oui j’avais connaissance de pouvoir pousser juste la valeur dans une info via event il me semble :slight_smile:
Zut si je t’ai posé une colle :slight_smile:

Voila, par exemple ou bien via du code php.

Oh bah je suis très loin d’être le mieux calé en terme de dev sur le community, quelqu’un aura peut etre une solution pour toi :wink:

Par contre fonctionnellement ça sert à quoi ces cases ?

Avec ma solution (qui est quand même complexe, je dois bien l’avouer), il suffira de créer une commande info par case et de pousser la nouvelle valeur via un script php dédié

Ces cases permettent d’avoir non seulement un visuel rapide de quand l’action se déroule (en mode planificatio), et de pouvoir soit l’activer soit l’activer sans farfouiller

Non mais en fait, ma question était plutôt : ça sert à programmer quoi ?

Merci @TonioBDS. Si on part sur le principe qu’il y a une commande info par case, je ne pourrais effectuer aucune action en cliquant dessus nous sommes d’accord ?
En fait, le tableau sert d’indicateur visuel (en un seul coup d’oeil, je vois toute une planification) mais je peux aussi la modifier. Dans l’exemple que j’ai donné au dessus, je pourrai par exemple venir cliquer sur la case Lundi 8h pour la déselectionner. La commande info n’est qu’une info de mon point de vue non ?

J’aimerai utiliser ce genre de grille de planification pour le chauffe-eau aussi, la borne de recharge de la voiture, le seche linge, la machine à laver… Etc :wink:

Non non non,
Ce que je dis c’est qu’il est possible d’afficher ces cases à cocher dans l’état correspondant à celui du virtuel dédié pour ce besoin, mais quand tu cliques dessus, le script associé au HTML de la case envoie une requête vers un script en lui disant en gros : « la case n°7, il faut la décocher ». Et le script comprends et demande vient modifier la valeurs de la commande info du virtuel que tu auras créé pour l’occasion.

Ah oui, alors à ce niveau la, je ne sais pas du tout par quel bout commencer :slight_smile:

Il faut que tu lises le post que j’ai cité dans mon premier message pour comprendre ce qui était fait.
Ensuite que tu commence petit, avec seulement 2 cases à cocher.
Et puis fais-toi aider par chatGPT pour ajouter le script JS à ton HTML et adapter le script PHP, moi ça m’a bien servi !!
Je pourrai tenter de t’aider aussi évidemment !

Hello,

Je pense que c’est possible avec un widget dédié qui stockerai dans sa commande (info/autre) les infos en mode tableau (json), mais c’est assez complexe. En plus il faut aussi rajouter cette complexité au scénario pour qu’il décode ainsi l’info.

EDIT : Ce widget est disponible sur mon Github :
https://phpvarious.github.io/documentation/widget/fr_FR/action/message/cmd.action.message.table_checkbox/


Bon avec un widget et scénario dédiés c’est tout a fait possible :

WIDGET

cmd.action.message.table_checkbox.html.txt (16,7 Ko)

supprimer l’extension .txt et à placer dans data/customTemplates/dashboard/

version code
<div class="cmd cmd-widget reportModeHidden" data-type="action" data-subtype="message" data-template="default" data-cmd_id="#id#" data-cmd_uid="#uid#" data-version="#version#" data-eqLogic_id="#eqLogic_id#">
    <!-- Widget name : cmd.action.message.table_checkbox
    Auteur        : Phpvarious
    Version actuelle : 06/08/2025
    Lien          : https://community.jeedom.com/t/tableau-avec-case-a-cocher-et-action-a-la-coche-ou-decoche/142387
  -->
  <div class="title #hide_name#">
    <div class="cmdName">#name_display#</div>
  </div>
  <div class="content">
    <div id ="tableContainer_#uid#"></div>
    <a class="btn btn-sm btn-success disabled" id="bt_#uid#_save" style="color: var(--sc-lightTxt-color) !important;background-color: var(--al-success-color) !important;"><i class="fas fa-check-circle"></i> Enregistrer</a>
  </div>
  <template>
    <div></div>
    <div>rows : {{Nom des lignes séparés par le caractère}} | ({{Ex : Lundi|Mardi|Mercredi}}).</div>
    <div>columns : {{Nom des colonnes séparés par le caractère}} | ({{Ex : 8h|10h|12h}}).</div>
    <div>type : Type de widget | (checkbox ou switch).</div>
    <div>┌───────── Checkbox ─────────</div>
    <div>&nbsp;| widthCheckbox : Taille de la checkbox. (Ex:20 | Défaut : 15)</div>
    <div>&nbsp;| radiusCheckbox : arrondis de la checkbox en % (Ex : 50 (= rond) | Défaut : 0)</div>
    <div>&nbsp;| ──── Défaut checkbox ────</div>
    <div>&nbsp;| checkedColor : Couleur de la checkbox (V) par défaut. (Ex: red, #ffffff)</div>
    <div>&nbsp;| checkedBackground : Couleur de fond de la checkBox par défaut si activée. (Ex: red, #ffffff)</div>
    <div>&nbsp;| notCheckedBackground : Couleur de fond de la checkBox par défaut si désactivée. (Ex: red, #ffffff)</div>
    <div>&nbsp;| ──── Checkbox modified and checked ────</div>
    <div>&nbsp;| checkedModifyColor : Couleur "V" de la checkbox en cas de modification et si checkée. (Ex: red, #ffffff)</div>
    <div>&nbsp;| checkedModifyBackground : Couleur de fond de la checkBox en cas de modification et si checkée. (Ex: red, #ffffff)</div>
    <div>&nbsp;| ──── Checkbox modified and unchecked ────</div>
    <div>&nbsp;| notCheckedModifyBackground : Couleur de fond de la checkBox en cas de modification et si non checkée. (Ex: red, #ffffff)</div>
    <div>┌───────── Switch ─────────</div>
    <div>&nbsp;| widthSwitch : Taille du switch. (Ex:20 | Défaut : 40)</div>
    <div>&nbsp;| ──── Défaut switch ────</div>
    <div>&nbsp;| switchedBackground : Couleur de fond du switch commuté par défaut. (Ex: red, #ffffff)</div>
    <div>&nbsp;| switchedColor : Couleur de la pastille commutée par défaut. (Ex: red, #ffffff)</div>
    <div>&nbsp;| noSwitchedBackground : Couleur de fond du switch non commuté par défaut. (Ex: red, #ffffff)</div>
    <div>&nbsp;| noSwitchedColor : Couleur de la pastille non commutée par défaut. (Ex: red, #ffffff)</div>
    <div>&nbsp;| ──── Switch modified and switched ────</div>
    <div>&nbsp;| switchedModifyBackground : Couleur de fond du switch commuté et modifié. (Ex: red, #ffffff)</div>
    <div>&nbsp;| switchedModifyColor : Couleur de la pastille commutée et modifiée. (Ex: red, #ffffff)</div>
    <div>&nbsp;| ──── Switch modified and unswitched ────</div>
    <div>&nbsp;| noSwitchedModifyBackground : Couleur de fond du switch non commuté et modifié. (Ex: red, #ffffff)</div>
    <div>&nbsp;| noSwitchedModifyColor : Couleur de la pastille non commutée et modifiée. (Ex: red, #ffffff)</div>
    
  </template>
  <script>
    var debug#id# = ('#debug#' == 1) ? true : false;
    var obj_#uid# = ''
    
    var daysString = 'Ligne1|Ligne2|Ligne3|Ligne4|Ligne5'
    var timesString = 'colonne1|colonne2|colonne3|colonne4|colonne5'
    
    var type_#uid# = 'checkbox'
    
    if ('#rows#' != '#' + 'rows#') daysString = '#rows#'
    if ('#columns#' != '#' + 'columns#') timesString = '#columns#'
    if ('#type#' != '#' + 'type#') type_#uid# = '#type#'
    ///  Checkbox  \\\
    if ('#widthCheckbox#' != '#' + 'widthCheckbox#' && !isNaN('#widthCheckbox#')) document.documentElement.style.setProperty('--size_#uid#', '#widthCheckbox#'+'px')
    if ('#radiusCheckbox#' != '#' + 'radiusCheckbox#' && !isNaN('#radiusCheckbox#')) document.documentElement.style.setProperty('--checkBoxRadius_#uid#', '#radiusCheckbox#'+'%')
    if ('#checkedColor#' != '#' + 'checkedColor#') document.documentElement.style.setProperty('--checkedColor_#uid#', '#checkedColor#')
    if ('#checkedBackground#' != '#' + 'checkedBackground#') document.documentElement.style.setProperty('--checkedBackground_#uid#', '#checkedBackground#')
    if ('#notCheckedBackground#' != '#' + 'notCheckedBackground#') document.documentElement.style.setProperty('--notCheckedBackground_#uid#', '#notCheckedBackground#')
    if ('#checkedModifyColor#' != '#' + 'checkedModifyColor#') document.documentElement.style.setProperty('--checkedModifyColor_#uid#', '#checkedModifyColor#')
    if ('#checkedModifyBackground#' != '#' + 'checkedModifyBackground#') document.documentElement.style.setProperty('--checkedModifyBackground_#uid#', '#checkedModifyBackground#')
    if ('#notCheckedModifyBackground#' != '#' + 'notCheckedModifyBackground#') document.documentElement.style.setProperty('--notCheckedModifyBackground_#uid#', '#notCheckedModifyBackground#')
    ///  Switch  \\\
    if ('#widthSwitch#' != '#' + 'widthSwitch#' && !isNaN('#widthSwitch#')) document.documentElement.style.setProperty('--widthSwitch_#uid#', '#widthSwitch#'+'px')
    if ('#switchedBackground#' != '#' + 'switchedBackground#') document.documentElement.style.setProperty('--switchedBackground_#uid#', '#switchedBackground#')
    if ('#noSwitchedBackground#' != '#' + 'noSwitchedBackground#') document.documentElement.style.setProperty('--noSwitchedBackground_#uid#', '#noSwitchedBackground#')
    if ('#switchedColor#' != '#' + 'switchedColor#') document.documentElement.style.setProperty('--switchedColor_#uid#', '#switchedColor#')
    if ('#noSwitchedColor#' != '#' + 'noSwitchedColor#') document.documentElement.style.setProperty('--noSwitchedColor_#uid#', '#noSwitchedColor#')
    if ('#switchedModifyBackground#' != '#' + 'switchedModifyBackground#') document.documentElement.style.setProperty('--switchedModifyBackground_#uid#', '#switchedModifyBackground#')
    if ('#switchedModifyColor#' != '#' + 'switchedModifyColor#') document.documentElement.style.setProperty('--switchedModifyColor_#uid#', '#switchedModifyColor#')
    if ('#noSwitchedModifyBackground#' != '#' + 'noSwitchedModifyBackground#') document.documentElement.style.setProperty('--noSwitchedModifyBackground_#uid#', '#noSwitchedModifyBackground#')
    if ('#noSwitchedModifyColor#' != '#' + 'noSwitchedModifyColor#') document.documentElement.style.setProperty('--noSwitchedModifyColor_#uid#', '#noSwitchedModifyColor#')
    
    
    var daysArray = daysString.replace(/[^a-zA-Z0-9|]/g,'').split('|')
    var timesArray = timesString.replace(/[^a-zA-Z0-9|]/g,'').split('|')
    
    var newTableLayout = document.createElement('table')
    newTableLayout.addClass('table table-condensed')
    newTableLayout.setAttribute('id', 'table_#uid#')
    
    // THEAD //
    var thead = document.createElement('thead')
    var newTr = document.createElement('tr')
    newTr.insertAdjacentHTML('beforeend', '<td></td>')
    for (i = 0; i <= timesArray.length-1; i++) {
      var newTd = '<td data-line="0" data-column="' + i + '">' + timesArray[i] + '</td>'
      newTr.insertAdjacentHTML('beforeend', newTd)
    }
    thead.appendChild(newTr)
    newTableLayout.appendChild(thead)
    
    // TBODY //
    newTableLayout.appendChild(document.createElement('tbody'))
    for (i = 0; i <= daysArray.length-1; i++) {
      var newTr = document.createElement('tr')
      newTr.setAttribute('data-day', daysArray[i])
      newTr.insertAdjacentHTML('beforeend', '<td>' + daysArray[i] + '</td>')
      for (j = 0; j <= timesArray.length-1; j++) {
        if (type_#uid# == 'switch') {
          var newTd = '<td><input id="' + daysArray[i] + '_' + timesArray[j] + '_#uid#" class="switch_#uid# #uid#Attr" type="checkbox" data-l1key="' + daysArray[i] + '" data-l2key="' + timesArray[j] + '"/><label for="' + daysArray[i] + '_' + timesArray[j] + '_#uid#" class="binarySwitch#id#"></label></td>'
        } else {
          var newTd = '<td><input id="' + daysArray[i] + '_' + timesArray[j] + '_#uid#" class="#uid#Attr" type="checkbox" data-l1key="' + daysArray[i] + '" data-l2key="' + timesArray[j] + '"></td>'
        }
        newTr.insertAdjacentHTML('beforeend', newTd)
      }
      newTableLayout.tBodies[0].appendChild(newTr)
    }
    
    // INJECT DOM
    document.getElementById('tableContainer_#uid#').append(newTableLayout)
    
    // SAVE
    document.getElementById('bt_#uid#_save')?.addEventListener('click', function(event) {
      var value = document.getElementById('table_#uid#')?.getJeeValues('.#uid#Attr')[0] || ''
      if (value != '') {
        event.target.addClass('disabled')
        jeedom.cmd.execute({ id: '#id#', value: { title: '', message: JSON.stringify(value) } })
      }
    })
    
    // EVENT CHECKBOX
    document.getElementById('table_#uid#')?.addEventListener('change', function(event) {
      if (event.target.getAttribute('type') == 'checkbox') {
        // checkbox
        event.target.setAttribute('data-checked', event.target.checked)
        if (isset(event.target.getAttribute('data-l1key')) && isset(event.target.getAttribute('data-l2key'))) {
          if (isset(obj[event.target.getAttribute('data-l1key')]) && isset(obj[event.target.getAttribute('data-l1key')][event.target.getAttribute('data-l2key')])) {
            if (obj[event.target.getAttribute('data-l1key')][event.target.getAttribute('data-l2key')] != event.target.checked) event.target.addClass('modify')
            else event.target.removeClass('modify')
          } else {
            event.target.addClass('modify')
          }
        }
        // save button
        let value = document.getElementById('table_#uid#')?.getJeeValues('.#uid#Attr')[0] || ''
        if (JSON.stringify(obj) != JSON.stringify(value)) {
          document.getElementById('bt_#uid#_save').removeClass('disabled')
        } else {
          document.getElementById('table_#uid#').querySelectorAll('input[type=checkbox]').removeClass('modify')
          document.getElementById('bt_#uid#_save').addClass('disabled')
        }
      }
    })
    
    // UPDATE
    jeedom.cmd.addUpdateFunction('#id#', function(_options) {
      if (debug#id#) console.log('┌─────────────────── Widget checkbox [#id#] en debug [addUpdateFunction()] ───────────────')
      if (debug#id#) console.table(_options)
      if (is_object(cmd = document.querySelector('.cmd[data-cmd_uid="#uid#"]'))) {
        try {
          obj = JSON.parse(_options.display_value)
          document.getElementById('table_#uid#')?.setJeeValues(obj, '.#uid#Attr')
          document.getElementById('tableContainer_#uid#').querySelectorAll('input[type=checkbox]').forEach(_checkbox => {
            if (isset(_checkbox.getAttribute('data-l1key')) && isset(_checkbox.getAttribute('data-l2key'))) {
              if (isset(obj[_checkbox.getAttribute('data-l1key')]) && isset(obj[_checkbox.getAttribute('data-l1key')][_checkbox.getAttribute('data-l2key')])) {
                if (obj[_checkbox.getAttribute('data-l1key')][_checkbox.getAttribute('data-l2key')] != _checkbox.checked) _checkbox.addClass('modify')
                else _checkbox.removeClass('modify')
              } else {
                _checkbox.setAttribute('data-checked', false)
                _checkbox.addClass('modify')
              }
            }
          })
          let value = document.getElementById('table_#uid#')?.getJeeValues('.#uid#Attr')[0] || ''
          if (JSON.stringify(obj) != JSON.stringify(value)) {
            document.getElementById('bt_#uid#_save').removeClass('disabled')
          }
        } catch (ex) {
          if (_options.display_value == '') {
            obj = ''
            document.getElementById('tableContainer_#uid#').querySelectorAll('input[type=checkbox]').forEach(_checkbox => {
              _checkbox.setAttribute('data-checked', false)
              _checkbox.addClass('modify')
              document.getElementById('bt_#uid#_save').removeClass('disabled')
            })
          } else {
            if (debug#id#) console.log('Erreur lors du parse de la valeur, verifiez la console error')
            console.error(ex);
          }
        }
      }
    })
    
    // INIT
    jeedom.cmd.refreshValue([{ cmd_id: '#id#', value: '#value#', display_value: '#state#', valueDate: '#valueDate#', collectDate: '#collectDate#', alertLevel: '#alertLevel#', unit: '#unite#' }])
  </script>
  
  <style>
    :root {
      --checkedColor_#uid#: var(--txt-color);
      --checkedBackground_#uid#: var(--btn-default-color);
      --notCheckedBackground_#uid#: var(--btn-default-color);
      
      --checkedModifyColor_#uid#: var(--al-warning-color);
      --checkedModifyBackground_#uid#: var(--btn-default-color);
      --notCheckedModifyBackground_#uid#: var(--al-warning-color);
      --size_#uid#: 15px;
      --checkBoxRadius_#uid#: 0%;
      
      --widthSwitch_#uid#: 40px;      
      --switchedBackground_#uid# : var(--bt-success-color);
      --switchedColor_#uid# : #ffffff;
      --noSwitchedBackground_#uid# : var(--btn-default-color);
      --noSwitchedColor_#uid# : #ffffff;
      --switchedModifyBackground_#uid#: var(--al-warning-color);
      --switchedModifyColor_#uid#: #ffffff;
      --noSwitchedModifyBackground_#uid#: var(--al-warning-color);
      --noSwitchedModifyColor_#uid#: #ffffff;
    }
    table#table_#uid# input[type=checkbox][data-checked='false'].modify {
      background: var(--notCheckedModifyBackground_#uid#) !important;
    }
    table#table_#uid# input[type=checkbox][data-checked='true'].modify {
      color: var(--checkedModifyColor_#uid#) !important;
      background: var(--checkedModifyBackground_#uid#) !important;
    }
    table#table_#uid# input[type=checkbox]:not(.switch_#uid#) {
      margin: 5px !important;
      color: var(--checkedColor_#uid#);
      background: var(--btn-default-color); !important;
      width: var(--size_#uid#) !important;
      height: var(--size_#uid#);
      font-size: calc(var(--size_#uid#) - 1px) !important;
      border-radius : var(--checkBoxRadius_#uid#) !important;
    }
    table#table_#uid# input[type=checkbox][data-checked='true'] {
      background: var(--checkedBackground_#uid#) !important;
    }
    table#table_#uid# input[type=checkbox][data-checked='false'] {
      background: var(--notCheckedBackground_#uid#) !important;
    }
    table#table_#uid# td {
      text-align: center;
    }
    
    table#table_#uid# input.switch_#uid# {
      visibility: hidden;
      position: absolute;
    }
    .binarySwitch#id# {
	  cursor: pointer;
	  text-indent: -9999px;
	  width: var(--widthSwitch_#uid#);
	  height: calc(var(--widthSwitch_#uid#) / 2);
	  background-color: var(--btn-default-color);
      border-radius: 50px;
	  position: relative;
      margin-bottom: 0px; /* pour contrer le boostrap */
    }
    table#table_#uid# input[data-checked='true'] + label.binarySwitch#id# {
	  background: var(--switchedBackground_#uid#);
    }
    table#table_#uid# input[data-checked='false'] + label.binarySwitch#id# {
	  background: var(--noSwitchedBackground_#uid#);
    }
    table#table_#uid# input[type=checkbox][data-checked='true'].modify + .binarySwitch#id# {
      background: var(--switchedModifyBackground_#uid#);
    }
    table#table_#uid# input[type=checkbox][data-checked='false'].modify + .binarySwitch#id# {
      background: var(--noSwitchedModifyBackground_#uid#);
    }
    label.binarySwitch#id#::after {
	  content: '';
	  position: absolute;
	  top: 3px;
	  left: 5px;
	  width: calc((var(--widthSwitch_#uid#) / 2) - 6px);
	  height: calc((var(--widthSwitch_#uid#) / 2) - 6px);
      background: #ffffff;
	  border-radius: 40px;
	  transition: 0.3s;
    }
    label.binarySwitch#id#:active:after {
	  width: 30px;
    }
    table#table_#uid# input[type=checkbox][data-checked='true'] + label.binarySwitch#id#::after {
      background: var(--switchedColor_#uid#);
      left: calc(100% - 5px);
	  transform: translateX(-100%);
    }
    table#table_#uid# input[type=checkbox][data-checked='false'] + label.binarySwitch#id#::after {
      background: var(--noSwitchedColor_#uid#);
    }
    table#table_#uid# input[type=checkbox][data-checked='true'].modify + label.binarySwitch#id#::after {
      background: var(--switchedModifyColor_#uid#);
    }
    table#table_#uid# input[type=checkbox][data-checked='false'].modify + label.binarySwitch#id#::after {
      background: var(--noSwitchedModifyColor_#uid#);
    }
  </style>
</div>

VIRTUEL

info/Autre (ne pas historiser) et peut être masqué.

action/Message lié a la commande info/Autre (tableau)

Dans la configuration de la commande action/Message appliquer le widget table_checkbox

Ensuite il faudra ajouter 2 paramètres optionnels rows et columns, pour ton exemple :

Il faudra paramètrer comme ceci :
image

UTILISATION


Au 1er affichage, vu qu’il n’y a encore eu aucune sauvegarde, toutes les checkbox sont vides et oranges, et la case Enregistrer est active :

image

Il suffit simplement d’activer les checkbox que tu souhaites :

image
Une fois sauvegardé, les checkbox reprendrons une couleur standard :

image

En gros, quand quelque chose est orange, c’est qu’il y a eu modification d’une checkbox, et qu’il est nécessaire de sauvegarder.

Pour afficher des switchs a la place des checkboxs, ajouter le paramètre optionnel type avec comme valeur switch :

image

Toutes les couleurs sont personnalisable dans le widget :

SCENARIO


Le scénario est assez simple, il mettra a disposition des tag contenant la valeur de la checkbox (0 ou 1), il est possible de voir les tag créés dans les log.
Il n’y a pas besoin de modifier ce scénario, même si tu ajoutes/modifie des paramètres optionnels du widget.

Pour notre exemple, il en sortira les tags suivant :

Log
[2025-08-03 22:12:40][SCENARIO] tag(Lundi_8h) = 1
[2025-08-03 22:12:40][SCENARIO] tag(Lundi_10h) = 0
[2025-08-03 22:12:40][SCENARIO] tag(Lundi_12h) = 0
[2025-08-03 22:12:40][SCENARIO] tag(Lundi_14h) = 0
[2025-08-03 22:12:40][SCENARIO] tag(Mardi_8h) = 0
[2025-08-03 22:12:40][SCENARIO] tag(Mardi_10h) = 1
[2025-08-03 22:12:40][SCENARIO] tag(Mardi_12h) = 0
[2025-08-03 22:12:40][SCENARIO] tag(Mardi_14h) = 0
[2025-08-03 22:12:40][SCENARIO] tag(Jeudi_8h) = 0
[2025-08-03 22:12:40][SCENARIO] tag(Jeudi_10h) = 0
[2025-08-03 22:12:40][SCENARIO] tag(Jeudi_12h) = 1
[2025-08-03 22:12:40][SCENARIO] tag(Jeudi_14h) = 0
[2025-08-03 22:12:40][SCENARIO] tag(Vendredi_8h) = 0
[2025-08-03 22:12:40][SCENARIO] tag(Vendredi_10h) = 0
[2025-08-03 22:12:40][SCENARIO] tag(Vendredi_12h) = 0
[2025-08-03 22:12:40][SCENARIO] tag(Vendredi_14h) = 1

Création du scénario :

1er élément :
action / tag avec comme nom table_value (bien respecter le nom), indispensable pour le bon fonctionnement du scénario. et comme valeur, aller chercher la commande info/Autre (tableau) du virtuel.

2ème élément :

Bloc code
$tags = $scenario->getTags();
$Json = json_decode($tags['#table_value#'], true); // decodage du tag table_value
if(!is_array($Json)) {
  $scenario->setLog('tag table_value mal formatté ou vide');
} else {
  foreach ($Json as $row => $column) {
    foreach ($column as $key => $value) {
      $scenario->setLog('tag(' . $row . '_'. $key . ') = ' . $value);
      $tags['#' . $row . '_'. $key . '#'] = $value;
    }
  }
  $scenario->setTags($tags);
}

3ème élément (optionnel):
C’est juste pour l’exemple, je fait une condition pour vérifier si la checkbox Lundi_8h est checked.

14 « J'aime »