L
L
logdog902022-02-20 11:21:51
Vue.js
logdog90, 2022-02-20 11:21:51

Is it possible to add buttons to an array dynamically and click on them?

How to add a nested array with buttons to the data and hang a click handler on them?

<template>
  <div class="employees">
    <table class="employees-table">
      <thead class="employees-header">
        <tr class="employees-row">
          <th class="employees-column" v-for="title in titles" :key="title.id">
            {{ title.label }}
          </th>
        </tr>
      </thead>
      <tbody class="employees-body">
        <tr
          class="employees-row"
          v-for="employee in employees"
          :key="employee.id"
        >
          <td
            class="employees-column"
            v-for="title in titles"
            :key="title.id"
            :data-label="title.label"
          >
            {{ employee[title.key] }}
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</template>

<script>
export default {
  data: () => ({
    titles: [
      { key: "name", label: "ФИО" },
      { key: "department", label: "Отдел" },
      { key: "position", label: "Должность" },
      { key: "hostname", label: "Имя ПК" },
      { key: "username", label: "Учётка" },
      { key: "actions", label: "Действия" }
    ],
    employees: [
      {
        name: "Пупкин Иван Петрович",
        department: "Отдел маркетинга",
        position: "Контент-менеджер",
        hostname: "of-vl-mar-001",
        username: "mar.001",
        actions: [] // Здесь должны быть кнопки, например редактировать и удалить 
      },
      {
        name: "Макиевская Ольга Николаевна",
        department: "Отдел маркетинга",
        position: "Дизайнер",
        hostname: "of-vl-mar-002",
        username: "mar.002",
        actions: [] // Здесь должны быть кнопки, например редактировать и удалить
      }
    ],
  }),
};
</script>

<style scoped>
.employees {
  display: flex;
  justify-content: center;
}

table {
  border: 1px solid #ccc;
  border-collapse: collapse;
  margin: 30px 0 0 0;
  padding: 0;
  width: 100%;
  table-layout: fixed;
}

table tr {
  border: 1px solid #4c9bf4;
  padding: 0.35em;
}

table th,
table td {
  padding: 0.625em;
  text-align: center;
}

table th {
  background-color: rgba(0, 113, 240, 0.7);
  font-size: 0.85em;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #fff;
}

.bi-x-circle-fill {
  color: red;
}

.bi-pencil-square {
  color: rgba(124, 124, 124, 0.7);
}

@media screen and (max-width: 600px) {
  table {
    border: 0;
    margin-top: 20px;
  }

  table thead {
    border: none;
    clip: rect(0 0 0 0);
    height: 1px;
    margin: -1px;
    overflow: hidden;
    padding: 0;
    position: absolute;
    width: 1px;
  }

  table tr {
    border-bottom: 3px solid rgba(0, 113, 240, 0.7);
    display: block;
    margin-bottom: 0.625em;
  }

  table td {
    border-bottom: 1px solid rgba(0, 113, 240, 0.7);
    display: block;
    font-size: 0.8em;
    text-align: right;
  }

  table td::before {
    /*
    * aria-label has no advantage, it won't be read inside a table
    content: attr(aria-label);
    */
    content: attr(data-label);
    float: left;
    font-weight: bold;
    text-transform: uppercase;
  }

  table td:last-child {
    border-bottom: 0;
  }
}
</style>

Answer the question

In order to leave comments, you need to log in

1 answer(s)
0
0xD34F, 2022-02-20
@logdog90

Let the actions be represented as an array of strings:

data: () => ({
  employees: [
    { ..., actions: [ 'delete', 'ещё что-то', 'и ещё' ] },
    ...
  ],
  ...

The table should be formatted as a separate component; for each of the columns, allocate a separate slot into which the row and column data and their indices will be transferred; by default, slots output data as it is:
props: {
  columns: Array,
  data: Array,
},

<table>
  <thead>
    <tr>
      <th v-for="(col, colIndex) in columns" :key="col.key">{{ col.label }}</th>
    </tr>
  </thead>
  <tbody>
    <tr v-for="(row, rowIndex) in data" :key="row.id">
      <td
        v-for="col in columns"
        :key="col.key"
        :data-label="col.label"
      >
        <slot
          :name="`column.${col.key}`"
          :col-data="col"
          :col-index="colIndex"
          :row-data="row"
          :row-index="rowIndex"
        >
          {{ row[col.key] }}
        </slot>
      </td>
    </tr>
  </tbody>
</table>

Well, then just pass the corresponding buttons to the slot of the actions column:
<v-table :columns="titles" :data="employees">
  <template #column.actions="{ rowData, rowIndex }">
    <div>
      <button
        v-for="action in rowData.actions"
        v-text="action"
        @click="onActionClick(action, rowData, rowIndex)"
      ></button>
    </div>
  </template>
</v-table>

methods: {
  onActionClick(action, row, index) {
    switch (action) {
      case 'delete':
        this.employees.splice(index, 1);
        return;

      case 'ещё что-то':
        this.сделатьЧтоТоЕщё(row);
        return;
    }
  },
  ...

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question