vue.jsheadervuetify.js

Vue 3 - Vuetify 3 Headers not appearing


Ive tried about every different way I can think of to make the headers in this data-table to show up. Everything else works, just no headers.... Any ideas greatly appreciated

Feels like this should be a pretty simple thing to do.

The Sorting arrows appear on hover in the header area. I've tried both title and text in the headers data array. Ive also tried hard coding them into the template.... No Joy

<template>
<v-container>
<v-row>
  <v-col>
    <v-btn color="primary" @click="fetchReports" class="mb-4">Refresh</v-btn>

    <!-- Data Table -->
    <v-data-table
      :headers="headers"
      :items="reports"
      class="elevation-3 observation-table"
      dense
      outlined
      rounded
    >
      <!-- Explicit header slots -->
      <template #column.id>
        <strong>ID</strong>
      </template>
      <template #column.user>
        <strong>User</strong>
      </template>
      <template #column.report_date>
        <strong>Report Date</strong>
      </template>
      <template #column.location>
        <strong>Location</strong>
      </template>

      <!-- Body Rows -->
      <template #body="{ items }">
        <tr
          v-for="item in items"
          :key="item.id"
          @click="viewReport(item)"
          class="clickable-row"
        >
          <td>{{ item.id }}</td>
          <td>{{ item.user }}</td>
          <td>{{ formatDate(item.report_date) }}</td>
          <td>{{ item.location }}</td>
        </tr>
      </template>
    </v-data-table>


    <!-- Button to Navigate to Form -->
    <v-btn color="primary" class="mt-4" @click="navigateToForm">
      Create Observation Report
      </v-btn>
     </v-col>
   </v-row>
  </v-container>
</template>

<script>
import axios from "axios";

export default {
  data() {
    return {
      reports: [],
      headers: [
        { text: "ID", value: "id" },
        { text: "User", value: "user" },
        { text: "Report Date", value: "report_date" },
        { text: "Location", value: "location" },
      ],
      search: "",
    };
  },
  methods: {
    async fetchReports() {
      try {
        const token = localStorage.getItem("accessToken");
        if (!token) throw new Error("Token is missing. Please log in.");
        const response = await axios.get(`/api/observationreports`, {
          headers: { Authorization: `Bearer ${token}` },
        });
        this.reports = response.data.map((report) => ({
          id: report.id,
          user: `${report.first_name} ${report.last_name}`,
          report_date: report.report_date,
          location: report.location,
        }));
        console.log("Headers:", this.headers);
      } catch (error) {
        console.error("Error fetching observation reports:", error.message);
      }
    },
    mounted() {
    console.log("Headers array:", this.headers); // Debugging headers array
    this.fetchReports();
  },
};
</script>

Well it wants me to add more details so Im not sure what else to add. Pretty clear what im having trouble with.... :(

Original - Sorry for the wall of code:

<template>
  <v-container>
    <v-row>
      <v-col>
        <v-btn color="primary" @click="fetchReports" class="mb-4">Refresh</v-btn>

        <!-- Data Table -->
        <v-data-table
          :headers="headers"
          :items="reports"
          class="elevation-3 observation-table"
          dense
          outlined
          rounded
        >
          <!-- Toolbar for title and search -->
          <template v-slot:top>
            <v-toolbar flat>
              <v-toolbar-title>Observation Reports</v-toolbar-title>
              <v-spacer></v-spacer>
              <v-text-field
                v-model="search"
                label="Search"
                single-line
                hide-details
                outlined
                dense
                style="max-width: 300px;"
              ></v-text-field>
            </v-toolbar>
          </template>

          <!-- Custom body for clickable rows -->
          <template #body="{ items }">
            <tbody>
              <tr
                v-for="item in items"
                :key="item.id"
                @click="viewReport(item)"
                class="clickable-row"
              >
                <td>{{ item.id }}</td>
                <td>{{ item.user }}</td>
                <td>{{ formatDate(item.report_date) }}</td>
                <td>{{ item.location }}</td>
              </tr>
            </tbody>
          </template>
        </v-data-table>

        <!-- Button to Navigate to Form -->
        <v-btn color="primary" class="mt-4" @click="navigateToForm">
          Create Observation Report
        </v-btn>
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
import axios from "axios";

export default {
  data() {
    return {
      reports: [],
      headers: [
        { text: "ID", value: "id" },
        { text: "User", value: "user" },
        { text: "Report Date", value: "report_date" },
        { text: "Location", value: "location" },
      ],
      search: "",
    };
  },
  methods: {
    async fetchReports() {
      try {
        const token = localStorage.getItem("accessToken");
        if (!token) throw new Error("Token is missing. Please log in.");
        const response = await axios.get(`/api/observationreports`, {
          headers: { Authorization: `Bearer ${token}` },
        });
        this.reports = response.data.map((report) => ({
          id: report.id,
          user: `${report.first_name} ${report.last_name}`,
          report_date: report.report_date,
          location: report.location,
        }));
      } catch (error) {
        console.error("Error fetching observation reports:", error.message);
      }
    },
    navigateToForm() {
      this.$router.push({ name: "ObservationReportForm" });
    },
    viewReport(report) {
      this.$router.push({ name: "CompletedObservationReport", params: { id: report.id } });
    },
    formatDate(dateString) {
      if (!dateString) return "N/A";
      const options = { year: "numeric", month: "short", day: "numeric" };
      return new Date(dateString).toLocaleDateString(undefined, options);
    },
  },
  mounted() {
    console.log("Headers array:", this.headers); // Debugging headers array
    this.fetchReports();
  },
};
</script>

<style scoped>
.observation-table {
  width: 100%;
}
</style>


Solution

  • In Vuetify 3, the slots for headers are named header.${string} (see docs), not column.${string} (I think that's Vuetify 2?).

    Just change to

    <template #header.id>
      <strong>ID</strong>
    </template>
    <template #header.user>
      <strong>User</strong>
    </template>
    ...
    

    playground