2

I'm trying to get the header on my QTable to be sticky. I have used the code from the Quasar documentation into my project and only my template at the top of the table is sticky while the header of the table is not. After a lot of playing around and experimenting with different code from people, I still have not been able to accomplish what I want to do. Any help would be appreciated. Component code is below:

<template>
  <div>
    <q-toolbar class="bg-grey-1 text-subtitle1 text-blue-grey-8 shadow-2 rounded-borders">
      <q-breadcrumbs class="text-grey" active-color="primary">
        <template v-slot:separator>
          <q-icon size="24px" name="arrow_forward" color="primary" />
        </template>

        <q-breadcrumbs-el
          label="Settings"
          icon="settings"
          class="hover cursor-pointer"
          @click="$router.push('/system')"
        />
        <q-breadcrumbs-el label="Course" class="text-primary" icon="class" />
      </q-breadcrumbs>
    </q-toolbar>
    <q-table
      class="q-mt-sm my-sticky-virtscroll-table"
      :columns="columns"
      :data.sync="getData"
      :pagination.sync="serverPagination"
      row-key="id"
      selection="single"
      :selected.sync="selected"
      @request="request"
    >
      <template slot="top">
        <q-btn dense color="primary" icon="arrow_drop_down" class="q-mr-sm"></q-btn>
        <q-input
          v-model="filter"
          placeholder="Search by Academic Program"
          type="text"
          class="col-3"
          @keypress.enter.native="search"
        />
        <q-btn
          class="q-pl-sm q-pr-sm"
          color="primary"
          flat
          @click="$refs.addCourse.toggle()"
        >
          <q-icon name="fas fa-plus" />
          <q-tooltip
            anchor="top middle"
            self="bottom middle"
            :offset="[10, 10]"
          >
            <strong>Add new Course</strong>
          </q-tooltip>
        </q-btn>
        <q-btn
          class="q-pl-sm"
          color="primary"
          :disable="!selected.length"
          flat
          @click="$refs.editCourse.toggle(selected[0])"
        >
          <q-icon name="fas fa-pencil-alt" />
          <q-tooltip
            anchor="top middle"
            self="bottom middle"
            :offset="[10, 10]"
          >
            <strong>Edit Course</strong>
            <br />Select record first
          </q-tooltip>
        </q-btn>
        <div class="col" />
        <q-btn
          color="negative"
          :disable="!selected.length"
          flat
          round
          @click="$refs.deleteCourse.toggle()"
        >
          <q-icon name="fas fa-trash-alt" />
          <q-tooltip
            anchor="top middle"
            self="bottom middle"
            :offset="[10, 10]"
          >
            <strong>Delete Course</strong>
            <br />Select record first
          </q-tooltip>
        </q-btn>
      </template>
    </q-table>
    <addCourse ref="addCourse"></addCourse>
    <editCourse :data="this.selected" ref="editCourse"></editCourse>
    <deleteCourse ref="deleteCourse"></deleteCourse>
  </div>
</template>

<script lang="ts">
import { Vue, Component } from 'vue-property-decorator'
import AddCourse from './AddCourse.vue'
import EditCourse from './EditCourse.vue'
import DeleteCourse from './DeleteCourse.vue'
import { Course, CourseModule, DataTablePagination } from '../../../store/course/index'

@Component({
  components: {
    addCourse: AddCourse,
    editCourse: EditCourse,
    deleteCourse: DeleteCourse
  }
})
export default class ManageCourse extends Vue {
  private filter: string = ''
  private selected: Course [] = []
  private columns = [
    {
      name: 'name',
      label: 'Name',
      align: 'center',
      required: true,
      field: 'name',
      sortable: true
    },
    {
      name: 'code',
      label: 'Code',
      align: 'center',
      required: true,
      field: 'code',
      sortable: true
    },
    {
      name: 'creditHours',
      label: 'Credit Hours',
      align: 'center',
      required: true,
      field: 'creditHours'
    },
    {
      name: 'numberOfLabs',
      label: 'Number of Labs',
      align: 'center',
      required: true,
      field: 'numberOfLabs'
    },
    {
      name: 'contactHours',
      label: 'Contact Hours',
      align: 'center',
      required: true,
      field: 'contactHours'
    }
  ]

  get getData() {
    return CourseModule.courses
  }

  get serverPagination() {
    return CourseModule.pagination
  }

  set serverPagination(value: DataTablePagination) {
    CourseModule.SET_PAGINATION(value)
  }

  request(args: any) {
    CourseModule.SET_PAGINATION(args.pagination)
    CourseModule.fetchCourses()
  }

  search() {
    CourseModule.SET_FILTER(this.filter)
    CourseModule.fetchCourses()
  }

  beforeMount() {
    CourseModule.fetchCourses()
  }
}
</script>

<style scoped lang="sass">
.my-sticky-virtscroll-table
  /* height or max-height is important */
  height: calc(100vh - 150px)

  .q-table__top,
  .q-table__bottom,
  thead tr:first-child th /* bg color is important for th; just specify one */
    background-color: #fff

  thead tr th
    position: sticky
    z-index: 1
  /* this will be the loading indicator */
  thead tr:last-child th
    /* height of all previous header rows */
    top: 48px
  thead tr:first-child th
    top: 0
</style>
Jeffrey penner
  • 155
  • 1
  • 4
  • 17

2 Answers2

1

It's a Vue scoped-css thing.

By default, the scoped styles won't affect child components, unless you add the special deep combinator, which is >>>. For preprocessors, such as sass, use the /deep/ combinator alias or the ::v-deep pseudo-element.

So, you should do something like:

<style scoped lang="sass">
.my-sticky-virtscroll-table::v-deep
  /* height or max-height is important */
  height: calc(100vh - 150px)

  .q-table__top,
  .q-table__bottom,
  thead tr:first-child th /* bg color is important for th; just specify one */
    background-color: #fff

  /* ... */
</style>

Edit: use ::v-deep instead of the deprecated /deep/. See https://stackoverflow.com/a/55368933/645296

Leonidas A
  • 329
  • 2
  • 11
0
<style lang="sass">
.sticky-header
  /* height or max-height is important */
  max-height: 100vh

  .q-table__top,
  .q-table__bottom,
  thead tr:first-child th
    /* bg color is important for th; just specify one */
    background-color: #fff

  thead tr th
    position: sticky
    z-index: 1
  thead tr:first-child th
    top: 0

  /* this is when the loading indicator appears */
  &.q-table--loading thead tr:last-child th
    /* height of all previous header rows */
    top: 48px
</style>
<q-table class="sticky-header"></q-table>

https://quasar.dev/vue-components/table#Sticky-header%2Fcolumn

I think this will work for you.