Search code examples
vue.jsvuejs2quasar-frameworkquasar

Display value derived from field instead of field itself in q-table column


enter image description here

I have a role for a specific user with these numbers.

  1. Instead of number 1 it will display the word "Super Admin"
  2. Instead of number 2 it will display the word "Admin"
  3. Instead of number 2 it will display the word "User" and so on.

I am using q-table

     <q-table
              flat
              bordered
              title="USERS"
              :data="allUsers"
              :columns="columns"
              :filter="filter"
              :pagination.sync="initialPagination"
              row-key="id"
            >
              <template v-slot:top-right>
                <q-input
                  outlined
                  dense
                  debounce="300"
                  placeholder="Search"
                  v-model="filter"
                >
                  <template v-slot:append>
                    <q-icon name="search" />
                  </template>
                </q-input>
    
                <div class="q-pa-sm q-gutter-sm"></div>
                <q-btn
                  outline
                  color="white"
                  text-color="black"
                  @click="openCreateUserModal"
                  label="Create Users"
                />
              </template>
    
              <template v-slot:body="props">
                <q-tr :props="props">
                  <q-td
                    v-for="col in props.cols.filter(col => col.name !== 'actions')"
                    :key="col.name"
                  >
                    {{ col.value }}
                  </q-td>
    
                  <td key="actions">
                    <q-btn dense flat color="primary" field="edit" icon="edit" />
                    <q-btn
                      dense
                      flat
                      color="negative"
                      field="delete"
                      icon="delete"
                    />
                  </td>
                </q-tr>
              </template>
            </q-table>

The role in my column

 {
      name: "role",
      align: "center",
      label: "Role",
      field: "role",
      sortable: true
    },

Is this possible what I'm trying to achieve?


Solution

  • Column definition can contain format field to define a custom formatting function. The function is called with the 2 arguments - the value retrieved from field and row (which can be useful to create display values by combining data from multiple fields)

    const roleIdToRoleName = {
      1: "Super Admin",
      2: "Admin",
      3: "User"
    }
    
    ...
    { 
      name: "role", 
      align: "center", 
      label: "Role", 
      field: "role", 
      sortable: true, 
      format: (val, row) => roleIdToRoleName[val] 
    },
    

    This works out of the box if you do not override default rendering by providing body slot. This is problematic because you will loose a lot of provided functionality:

    1. field can be string but it can also be a function (useful to drill down to some nested object data)
    2. format is of course not applied

    Default "get cell value" functionality of q-table looks like something like this:

    const getCellValue(row, col) {
      const val = typeof col.field === 'function' ? col.field(row) : row[col.field]
      return col.format ? col.format(val, row) : val
    }
    

    You can of course replicate it in your code and use it:

    <q-td :props="props"  // !! you are missing props here
      v-for="col in props.cols.filter(col => col.name !== 'actions')"
      :key="col.name"
    >
      {{ getCellValue(props.row, col) }}
    </q-td>
    

    but since it seems only reason you are overriding body slot is because you need custom rendering of the actions column, why not just use body-cell-actions slot instead? This will override only rendering of actions column and other columns will use default q-table rendering

    Just add actions column in columns definition:

    { name: 'actions', label: 'Action', sortable: false}
    
     <template v-slot:body-cell-actions="props">
       <q-td :props="props">
         <q-btn dense flat color="primary" field="edit" icon="edit" />
         <q-btn dense flat color="negative" field="delete" icon="delete" />
       </q-td>
     </template>