Vuetify :: Abrir la fila de detalles de forma programada

Para el próximo lanzamiento de PiCockpit v2.0, estoy preparando una aplicación GPIO.

Las entradas GPIO son filas de la tabla - y para configurarlas, queremos ser capaces de acceder a la fila de detalle haciendo clic en el botón de configuración:

imagen

Al hacer clic en el chevron o en el botón de configuración, se abrirá la fila de detalles:

imagen

Aquí está la plantilla Vue correspondiente:

<v-tabla de datos
   :headers="gpioInputTableHeaders"
   :items="gpioInputTableData"
   :loading="loading"
   item-key="bcm_id"
   loading-text="esperando datos..."
   encabezado fijo
  show-expand
   :expanded.sync="gpioInputTableExpanded"

   class="elevación-1″
>
   <template v-slot:item.value=”{ item }”>
     <span v-if="”!onlineStateBinary”"><i class="”fa" fa-warning”></i> </span>
     <span v-if="”item.state" ><v-icon x-small>mdi-arrow-up-bold</v-icon>{{item.high}}</span>
     <span v-else-if="”item.state" ><v-icon x-small>mdi-arrow-down-bold</v-icon>{{item.low}}</span>
     <span v-else-if="”item.state" >N/A</span>
     <span v-else-if="”item.state" >N/A</span>
     <span v-else>ERROR</span>
   </template>
   <plantilla v-slot:item.action="{ item }">
     <v-btn
       class="mr-2″
       color="primario"
       pequeño
       @click.ctrl.exact="configGpioAll('input', item)"
       @click.exact="configGpio('input', item)"

     >
       llave de martillo de la IMD
       Configurar
     </v-btn>
     <v-btn
       class="mr-2″
       color="error"
       pequeño
       @click="remove_gpio('input', item.bcm_id)"
     >
       mdi-trash-can-outline
       Eliminar
     </v-btn>
   </template>
   <template v-slot:expanded-item=”{ headers, item }”>
     <!– v-on:pull-change=”pullChange” –>
     <td :colspan="”headers.length”">
       <gpioInputDetailRow
         :rowData="artículo"
         v-on:pull-change="pullChange"
         v-on:debounce-change="debounceChange"
       >
     </td>
   </template>       
</v-data-table>        

Como puede ver, envuelvo otro componente para la ranura del elemento expandido. Este componente es irrelevante para nuestra discusión actual, por lo que no proporciono código para él.

He resaltado las partes importantes más arriba.

Estos son:

  • :items="gpioInputTableData" - esto vincula los datos a la clave de artículos de la tabla de datos Vuetify
  • item-key="bcm_id" - esto es importante para dar una clave única para cada entrada de sus datos (que se da como una matriz a los elementos).
    • si omite esta configuración, todas las líneas de detalle se abrirán a la vez y se cerrarán a la vez.
    • el valor debe ser único como se ha dicho; en caso de que sus datos tengan potencialmente valores duplicados en todas las claves, debe crear una clave única adicional
  • show-expand - esto mostrará los chevrones imagen
  • :expanded.sync="gpioInputTableExpanded" - ¡nótese el uso del modificador sync, para sincronizar los cambios de vuelta! Esta es una variable para almacenar los elementos actualmente expandidos.

entonces:

  •  @click.ctrl.exact="configGpioAll('input', item)" - como puedes ver, al pulsar Ctrl + clic, estoy llamando a una función de utilidad para alternar todas las ranuras de expansión, dependiendo del estado del elemento actual. Le paso el ítem que debe ser expandido
  • @click.exact="configGpio('input', item)" - como ves, en un clic exacto, llamo a otra función de utilidad (llegaremos a ellas en breve), pasando TAMBIÉN el elemento actual

finalmente:

  • <template v-slot:expanded-item=”{ headers, item }”> - esta ranura contiene el elemento expandido. Es importante pasar las cabeceras:
  • <td :colspan="”headers.length”"> - ... porque permite crear una celda que abarque todas las columnas

Este es el aspecto de mi data() (extracto):

datos () {
   devolver {
     carga: verdadero,
     gpioInputTableData: [],
     gpioInputTableHeaders: [
       { texto: 'Nombre', valor: 'nombre'},
       { texto: 'Valor', valor: 'valor'},
       { texto: 'Acción', valor: 'acción'}
     ],
     gpioInputTableExpanded: []

  }
},

Y aquí están las dos funciones de utilidad:

imagen

configGpioAll: function (source, item){
         var ref = null;
         var refTable = null;
         if (source === 'input'){
             ref = 'gpioInputTableExpanded';
             refTable = 'gpioInputTableData';
         } else if (source === 'output'){
             ref = 'gpioOutputTableExpanded';
             refTable = 'gpioOutputTableData';
         } else if (source === 'softpwm'){
             ref = 'gpioSoftPWMTableExpanded';
             refTable = 'gpioSoftPWMTableData';
         }
         // ¿coincidimos con este artículo (está abierto?)
        if (this[ref].filter(e => e.bcm_id === item.bcm_id).length > 0){
           // eliminar todos los elementos
           console.log("configGpioAll: eliminando");
           este[ref] = [];
         }
         si no {
           console.log("configGpioAll: añadiendo");
           // añadir todos los elementos
           this[ref] = this[refTable];
         }
       },

en configGpioAll, compruebo si tengo la tabla de entrada, salida o softpwm (para evitar duplicar código), y configuro las referencias a la variable expandida apropiada (ver datos arriba), y los datos de la tabla en sí.

Si el elemento está contenido en los datos expandidos (coincido por mi clave única, bcm_id), cierro todos los elementos expandidos - para esto simplemente establezco la variable expandida a una matriz vacía.

Si el ítem NO está contenido en los datos expandidos, abro todos los ítems, poniendo todos los datos de la tabla.

Nota: podría valer la pena experimentar si una matriz de objetos que contenga sólo las claves únicas podría ser suficiente para que esto funcione también.

imagen

configGpio: function (source, item){
   var ref = null;
   if (source === 'input'){
       ref = 'gpioInputTableExpanded';
   } else if (source === 'output'){
       ref = 'gpioOutputTableExpanded';
   } else if (source === 'softpwm'){
       ref = 'gpioSoftPWMTableExpanded';
   }
   if (this[ref].filter(e => e.bcm_id === item.bcm_id).length > 0){
     // eliminar el elemento
     this[ref] = this[ref].filter(e => e.bcm_id !== item.bcm_id);
   }
   si no {
     // añadir el elemento
     this[ref].push(item);
   }
},

en configGpio, hago cosas similares - pero en vez de eliminar todos los elementos, filtro y elimino el elemento que coincide con el bcm_id que me han pasado.

Si el elemento no está presente, lo introduzco en la variable expandida.

Esta es la razón por la que necesito el elemento completo, no sólo el bcm_id. Elegí tener simetría en mi código, por lo que configGpioAll que técnicamente sólo necesita el bcm_id también obtiene el elemento completo.