Skip to content

Crud

Introduction to the view feature of the z-crud component

Basic Usage

Configure the detail field of column to configure the detail view.

<script lang="ts" setup>
import { ref } from 'vue'

const loading = ref(false)
const formData = ref({
  name: '',
  gender: '',
  age: '',
})
const tableData = ref([])

const columns = ref([
  {
    prop: 'name',
    label: 'Name',
    search: {
      component: 'input',
      label: 'Name',
      field: 'name',
    },
    detail: {
      field: 'name',
      label: 'Name',
    },
  },
  {
    prop: 'gender',
    label: 'Gender',
    search: {
      component: 'select',
      label: 'Gender',
      field: 'gender',
    },
    detail: {
      field: 'gender',
      label: 'Gender',
    },
  },
  {
    prop: 'age',
    label: 'Age',
    detail: {
      field: 'time',
      label: 'Date',
    },
    search: {
      component: 'input',
      label: 'Age',
      field: 'age',
    },
  },
  {
    prop: 'date',
    label: 'Date',
  },
])

const options = {
  gender: [{ label: 'male', value: 'male' }, { label: 'female', value: 'female' }],
}
const pagination = ref({
  page: 1,
  pageSize: 2,
  total: 4,
})
const request = ref({
  searchApi: mockApi,
})

function mockApi() {
  return new Promise((resolve) => {
    setTimeout(() => {
      const data = [
        {
          id: 1,
          name: 'Steven',
          gender: 'male',
          age: 22,
          date: '2020-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 2,
          name: 'Helen',
          gender: 'male',
          age: 12,
          date: '2012-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 3,
          name: 'Nancy',
          gender: 'female',
          age: 18,
          date: '2018-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 4,
          name: 'Jack',
          gender: 'male',
          age: 28,
          date: '2028-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
      ]

      resolve({
        data: {
          page: 1,
          pageSize: 10,
          total: 4,
          list: data.slice((pagination.value.page - 1) * pagination.value.pageSize, pagination.value.page * pagination.value.pageSize),
        },
      })
    }, 100)
  })
}
</script>

<template>
  <z-crud
    v-model:pagination="pagination"
    v-model:data="tableData"
    v-model:formData="formData"
    v-model:loading="loading"
    :options="options"
    :columns="columns"
    :add="false"
    :edit="false"
    :delete="false"
    :request="request"
  />
</template>

Configure the columns of detail to configure the detail view.

<script lang="ts" setup>
import { ref } from 'vue'

const loading = ref(false)
const formData = ref({
  name: '',
  gender: '',
  age: '',
})
const tableData = ref([])

const columns = ref([
  {
    prop: 'name',
    label: 'Name',
  },
  {
    prop: 'gender',
    label: 'Gender',
  },
  {
    prop: 'age',
    label: 'Age',
  },
  {
    prop: 'time',
    label: 'Date',
  },
])

const detailConfig = ref({
  columns: [{
    prop: 'name',
    label: 'Name',
  }, {
    prop: 'gender',
    label: 'Gender',
  }, {
    prop: 'date',
    label: 'Date',
  }],
})

const searchFormConfig = ref({
  labelWith: '80px',
  columns: [
    {
      component: 'input',
      label: 'Name',
      field: 'name',
    },
    {
      component: 'select',
      label: 'Gender',
      field: 'gender',
    },
    {
      component: 'input',
      label: 'Age',
      field: 'age',
    },
  ],
})

const options = {
  gender: [{ label: 'male', value: 'male' }, { label: 'female', value: 'female' }],
}
const pagination = ref({
  page: 1,
  pageSize: 2,
  total: 4,
})
const request = ref({
  searchApi: mockApi,
})

function mockApi() {
  return new Promise((resolve) => {
    setTimeout(() => {
      const data = [
        {
          id: 1,
          name: 'Steven',
          gender: 'male',
          age: 22,
          date: '2020-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 2,
          name: 'Helen',
          gender: 'male',
          age: 12,
          date: '2012-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 3,
          name: 'Nancy',
          gender: 'female',
          age: 18,
          date: '2018-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 4,
          name: 'Jack',
          gender: 'male',
          age: 28,
          date: '2028-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
      ]

      resolve({
        data: {
          page: 1,
          pageSize: 10,
          total: 4,
          list: data.slice((pagination.value.page - 1) * pagination.value.pageSize, pagination.value.page * pagination.value.pageSize),
        },
      })
    }, 100)
  })
}
</script>

<template>
  <z-crud
    v-model:pagination="pagination"
    v-model:data="tableData"
    v-model:formData="formData"
    v-model:loading="loading"
    :options="options"
    :columns="columns"
    :detail="detailConfig"
    :search="searchFormConfig"
    :add="false"
    :edit="false"
    :delete="false"
    :request="request"
  />
</template>

Configure the columns field of form to configure the detail view.

<script lang="ts" setup>
import { ref } from 'vue'

const loading = ref(false)
const formData = ref({
  name: '',
  gender: '',
  age: '',
})
const tableData = ref([])

const columns = ref([
  {
    prop: 'name',
    label: 'Name',
  },
  {
    prop: 'gender',
    label: 'Gender',
  },
  {
    prop: 'age',
    label: 'Age',
  },
  {
    prop: 'date',
    label: 'Date',
  },
])

const searchFormConfig = ref({
  labelWith: '80px',
  columns: [
    {
      component: 'input',
      label: 'Name',
      field: 'name',
    },
    {
      component: 'select',
      label: 'Gender',
      field: 'gender',
    },
    {
      component: 'input',
      label: 'Age',
      field: 'age',
    },
  ],
})

const options = {
  gender: [{ label: 'male', value: 'male' }, { label: 'female', value: 'female' }],
}
const pagination = ref({
  page: 1,
  pageSize: 2,
  total: 4,
})
const request = ref({
  searchApi: mockApi,
})

const formConfig = ref({
  columns: [
    {
      component: 'input',
      field: 'name',
      label: 'Name',
      required: true,
    },
    {
      component: 'select',
      field: 'gender',
      label: 'Gender',
    },
    {
      component: 'el-date-picker',
      field: 'time',
      label: 'Date',
      fieldProps: {
        type: 'daterange',
        startPlaceholder: 'Start date',
        endPlaceholder: 'End date',
      },
    },
  ],
})

function mockApi() {
  return new Promise((resolve) => {
    setTimeout(() => {
      const data = [
        {
          id: 1,
          name: 'Steven',
          gender: 'male',
          age: 22,
          date: '2020-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 2,
          name: 'Helen',
          gender: 'male',
          age: 12,
          date: '2012-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 3,
          name: 'Nancy',
          gender: 'female',
          age: 18,
          date: '2018-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 4,
          name: 'Jack',
          gender: 'male',
          age: 28,
          date: '2028-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
      ]

      resolve({
        data: {
          page: 1,
          pageSize: 10,
          total: 4,
          list: data.slice((pagination.value.page - 1) * pagination.value.pageSize, pagination.value.page * pagination.value.pageSize),
        },
      })
    }, 100)
  })
}
</script>

<template>
  <z-crud
    v-model:pagination="pagination"
    v-model:data="tableData"
    v-model:formData="formData"
    v-model:loading="loading"
    :options="options"
    :columns="columns"
    :search="searchFormConfig"
    :form="formConfig"
    :delete="false"
    :request="request"
  />
</template>

Configure the form field of a column item to configure the detail information, but this will also configure the query, add, and edit forms at the same time. You can set search, add, and edit to false to disable them.

<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { ref } from 'vue'
import type { EditRequestApiParams } from 'ideaz-element'

interface RowData {
  id: number
  name: string
  gender: string
  age: number
  date: string
  time: string[]
}

interface FormData {
  name: string
  gender: string
  age: string
}

const loading = ref(false)
const formData = ref({
  name: '',
  gender: '',
  age: '',
})
const tableData = ref([])

const columns = ref([
  {
    prop: 'name',
    label: 'Name',
    form: {
      component: 'input',
      field: 'name',
      label: 'Name',
      required: true,
    },
  },
  {
    prop: 'gender',
    label: 'Gender',
    form: {
      component: 'select',
      field: 'gender',
      label: 'Gender',
    },
  },
  {
    prop: 'age',
    label: 'Age',
    form: {
      component: 'el-date-picker',
      field: 'time',
      label: 'Date',
      fieldProps: {
        type: 'daterange',
        startPlaceholder: 'Start date',
        endPlaceholder: 'End date',
      },
    },
    search: false,
    add: false,
    edit: false,
  },
  {
    prop: 'date',
    label: 'Date',
  },
])

const options = {
  gender: [{ label: 'male', value: 'male' }, { label: 'female', value: 'female' }],
}
const pagination = ref({
  page: 1,
  pageSize: 2,
  total: 4,
})
const request = ref({
  searchApi: mockApi,
  addApi: commonApi,
  editApi: commonApi,
})

function mockApi() {
  return new Promise((resolve) => {
    setTimeout(() => {
      const data = [
        {
          id: 1,
          name: 'Steven',
          gender: 'male',
          age: 22,
          date: '2020-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 2,
          name: 'Helen',
          gender: 'male',
          age: 12,
          date: '2012-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 3,
          name: 'Nancy',
          gender: 'female',
          age: 18,
          date: '2018-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 4,
          name: 'Jack',
          gender: 'male',
          age: 28,
          date: '2028-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
      ]

      resolve({
        data: {
          page: 1,
          pageSize: 10,
          total: 4,
          list: data.slice((pagination.value.page - 1) * pagination.value.pageSize, pagination.value.page * pagination.value.pageSize),
        },
      })
    }, 100)
  })
}

function commonApi(params: EditRequestApiParams<FormData, RowData>) {
  console.log(params, 'commonApi params')
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve({
        msg: 'success',
        code: 200,
      })
    }, 100)
  })
}
</script>

<template>
  <z-crud
    v-model:pagination="pagination"
    v-model:data="tableData"
    v-model:formData="formData"
    v-model:loading="loading"
    :columns="columns"
    :options="options"
    :delete="false"
    :request="request"
  />
</template>

API Configuration

By default, the detail view uses the row data. If you need to call an API, please configure request.detailApi.

<script lang="ts" setup>
import { ref } from 'vue'

const loading = ref(false)
const formData = ref({
  name: '',
  gender: '',
  age: '',
})
const tableData = ref([])

const columns = ref([
  {
    prop: 'name',
    label: 'Name',
    search: {
      component: 'input',
      label: 'Name',
      field: 'name',
    },
    detail: {
      field: 'name',
      label: 'Name',
    },
  },
  {
    prop: 'gender',
    label: 'Gender',
    search: {
      component: 'select',
      label: 'Gender',
      field: 'gender',
    },
    detail: {
      field: 'gender',
      label: 'Gender',
    },
  },
  {
    prop: 'age',
    label: 'Age',
    detail: {
      field: 'time',
      label: 'Date',
    },
    search: {
      component: 'input',
      label: 'Age',
      field: 'age',
    },
  },
  {
    prop: 'date',
    label: 'Date',
  },
])

const options = {
  gender: [{ label: 'male', value: 'male' }, { label: 'female', value: 'female' }],
}
const pagination = ref({
  page: 1,
  pageSize: 2,
  total: 4,
})
const request = ref({
  searchApi: mockApi,
  detailApi,
})

function mockApi() {
  return new Promise((resolve) => {
    setTimeout(() => {
      const data = [
        {
          id: 1,
          name: 'Steven',
          gender: 'male',
          age: 22,
          date: '2020-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 2,
          name: 'Helen',
          gender: 'male',
          age: 12,
          date: '2012-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 3,
          name: 'Nancy',
          gender: 'female',
          age: 18,
          date: '2018-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 4,
          name: 'Jack',
          gender: 'male',
          age: 28,
          date: '2028-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
      ]

      resolve({
        data: {
          page: 1,
          pageSize: 10,
          total: 4,
          list: data.slice((pagination.value.page - 1) * pagination.value.pageSize, pagination.value.page * pagination.value.pageSize),
        },
      })
    }, 100)
  })
}

function detailApi() {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve({
        data: {
          id: 3,
          time: '2023-01-12',
          gender: 'male',
          name: 'David',
        },
      })
    }, 100)
  })
}
</script>

<template>
  <z-crud
    v-model:pagination="pagination"
    v-model:data="tableData"
    v-model:formData="formData"
    v-model:loading="loading"
    :options="options"
    :columns="columns"
    :delete="false"
    :add="false"
    :edit="false"
    :request="request"
  />
</template>

Drawer Configuration

el-drawer component attributes are passed directly through drawer.

<script lang="ts" setup>
import { ref } from 'vue'

const loading = ref(false)
const formData = ref({
  name: '',
  gender: '',
  age: '',
})
const tableData = ref([])

const columns = ref([
  {
    prop: 'name',
    label: 'Name',
    search: {
      component: 'input',
      label: 'Name',
      field: 'name',
    },
    detail: {
      field: 'name',
      label: 'Name',
    },
  },
  {
    prop: 'gender',
    label: 'Gender',
    search: {
      component: 'select',
      label: 'Gender',
      field: 'gender',
    },
    detail: {
      field: 'gender',
      label: 'Gender',
    },
  },
  {
    prop: 'age',
    label: 'Age',
    detail: {
      field: 'time',
      label: 'Date',
    },
    search: {
      component: 'input',
      label: 'Age',
      field: 'age',
    },
  },
  {
    prop: 'date',
    label: 'Date',
  },
])

const drawer = ref({
  title: 'View Details',
  showClose: false,
})

const options = {
  gender: [{ label: 'male', value: 'male' }, { label: 'female', value: 'female' }],
}
const pagination = ref({
  page: 1,
  pageSize: 2,
  total: 4,
})
const request = ref({
  searchApi: mockApi,
})

function mockApi() {
  return new Promise((resolve) => {
    setTimeout(() => {
      const data = [
        {
          id: 1,
          name: 'Steven',
          gender: 'male',
          age: 22,
          date: '2020-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 2,
          name: 'Helen',
          gender: 'male',
          age: 12,
          date: '2012-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 3,
          name: 'Nancy',
          gender: 'female',
          age: 18,
          date: '2018-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 4,
          name: 'Jack',
          gender: 'male',
          age: 28,
          date: '2028-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
      ]

      resolve({
        data: {
          page: 1,
          pageSize: 10,
          total: 4,
          list: data.slice((pagination.value.page - 1) * pagination.value.pageSize, pagination.value.page * pagination.value.pageSize),
        },
      })
    }, 100)
  })
}
</script>

<template>
  <z-crud
    v-model:pagination="pagination"
    v-model:data="tableData"
    v-model:formData="formData"
    v-model:loading="loading"
    :options="options"
    :columns="columns"
    :request="request"
    :delete="false"
    :add="false"
    :edit="false"
    :drawer="drawer"
  />
</template>

Custom View

Supports using the operate-view event or passing a function to detail to customize the follow-up logic after clicking the view button.

<!-- eslint-disable unused-imports/no-unused-vars -->
<script lang="ts" setup>
import { ref } from 'vue'
import { ElMessage } from 'element-plus'

const loading = ref(false)
const formData = ref({
  name: '',
  gender: '',
  age: '',
})
const tableData = ref([])

const columns = ref([
  {
    prop: 'name',
    label: 'Name',
    search: {
      component: 'input',
      label: 'Name',
      field: 'name',
    },
    detail: {
      field: 'name',
      label: 'Name',
    },
  },
  {
    prop: 'gender',
    label: 'Gender',
    search: {
      component: 'select',
      label: 'Gender',
      field: 'gender',
    },
    detail: {
      field: 'gender',
      label: 'Gender',
    },
  },
  {
    prop: 'age',
    label: 'Age',
    detail: {
      field: 'time',
      label: 'Date',
    },
    search: {
      component: 'input',
      label: 'Age',
      field: 'age',
    },
  },
  {
    prop: 'date',
    label: 'Date',
  },
])

const options = {
  gender: [{ label: 'male', value: 'male' }, { label: 'female', value: 'female' }],
}
const pagination = ref({
  page: 1,
  pageSize: 2,
  total: 4,
})
const request = ref({
  searchApi: mockApi,
})

function handleView({ row, tableRef }) {
  ElMessage.success('View action triggered')
}

function mockApi() {
  return new Promise((resolve) => {
    setTimeout(() => {
      const data = [
        {
          id: 1,
          name: 'Steven',
          gender: 'male',
          age: 22,
          date: '2020-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 2,
          name: 'Helen',
          gender: 'male',
          age: 12,
          date: '2012-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 3,
          name: 'Nancy',
          gender: 'female',
          age: 18,
          date: '2018-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 4,
          name: 'Jack',
          gender: 'male',
          age: 28,
          date: '2028-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
      ]

      resolve({
        data: {
          page: 1,
          pageSize: 10,
          total: 4,
          list: data.slice((pagination.value.page - 1) * pagination.value.pageSize, pagination.value.page * pagination.value.pageSize),
        },
      })
    }, 100)
  })
}
</script>

<template>
  <z-crud
    v-model:pagination="pagination"
    v-model:data="tableData"
    v-model:formData="formData"
    v-model:loading="loading"
    :options="options"
    :columns="columns"
    :add="false"
    :edit="false"
    :delete="false"
    :request="request"
    @operate-view="handleView"
  />
</template>
AttributeDescriptionTypeDefault
detailDetail configurationboolean / object / ({ row, tableRef }) => voidtrue
formConfiguration for query, add, edit, and view form attributesobject
actionWhether to display action items (built-in delete, edit and other buttons)booleantrue
editEdit configurationboolean / objecttrue
addAdd configurationboolean / objecttrue
deleteDelete configurationboolean / ({ row, tableRef, getTableData }) => void / objecttrue
searchSearch configurationboolean / object
drawerDrawer configurationobject
requestAPI configurationobject

detail Attributes

AttributeDescriptionTypeDefault
columnsForm itemsarray
borderWhether with borderbooleantrue
columnNumber of Descriptions Item in a rownumber1
directionDirection of arrangementenumhorizontal
sizeSize of the listenum
titleTitle text, displayed in the upper leftstring / () => VNode''
extraAction area text, displayed in the upper rightstring / () => VNode''

form Attributes

AttributeDescriptionTypeDefault
rulesForm validation rulesobject
columnsForm itemsarray
optionsData source of form optionsobject
colonColon of form itembooleanfalse
alignVertical alignment under flex layouttop / middle /bottom
label-positionPosition of form field labels. When set to left or right, you also need to set the label-width attributeenumright
label-widthLength of the label, e.g. '50px'. Form-items that are direct children of Form inherit this value. auto can be used.string / number''
label-suffixSuffix of the form field labelstring''
hide-required-asteriskWhether to hide the red asterisk next to required field labelsbooleanfalse
require-asterisk-positionPosition of the asteriskleft / rightleft
show-messageWhether to display validation error messagesbooleantrue
inline-messageWhether to display validation messages inlinebooleanfalse
status-iconWhether to display validation result feedback icons in the input boxbooleanfalse
validate-on-rule-changeWhether to trigger a validation immediately after the rules attribute changesbooleantrue
sizeSize used to control the components within this formlarge / default / small
disabledWhether to disable all components in this form. If set to true, it overrides internal components' disabledbooleanfalse
scroll-to-errorScroll to the first erroneous form item when validation failsbooleanfalse
scroll-into-view-optionsWhen there are failed validation results, scroll to the first failed form itemobject / boolean

request Attributes

AttributeDescriptionTypeDefault
searchApiSearch API(params: any) => promise
submitApiEdit and add confirmation({ [key: string]: any, row: any, type: 'add' / 'edit' / 'view', formData: any }) => promise
deleteApiDelete API({ [key: string]?: any, row?: any, selectionData?: any }) => promise
addApiAdd API({ type: 'add' / 'edit' / 'view', formData: any }) => promise
editApiEdit API({ [key: string]: any, row: any, type: 'add' / 'edit' / 'view', formData: any }) => promise
detailApiDetail API({ [key: string]: any, row: any }) => promise
aliasCustom data pathobject
beforeDataCallback before table data API callFunction
afterDataCallback after table data API call(res) => void
searchFuncOverride of search method({ params }) => any
tableDataCustom return of table data(res) => any

drawer Attributes

AttributeDescriptionTypeDefault
append-to-bodyWhether the Drawer itself is inserted into the body element. Nested Drawers must specify this property and set it to truebooleanfalse
lock-scrollWhether to lock body scrolling when Drawer appearsbooleantrue
before-closeCallback before closing; will pause Drawer closingFunction
close-on-click-modalWhether the Drawer can be closed by clicking the modalbooleantrue
close-on-press-escapeWhether the Drawer can be closed by pressing ESCbooleantrue
open-delayDelay time for Drawer opening, in millisecondsnumber0
close-delayDelay time for Drawer closing, in millisecondsnumber0
destroy-on-closeControls whether to destroy all child elements after closing Drawerbooleanfalse
modalWhether a mask layer is neededbooleantrue
directionOpening direction of the Drawerenumrtl
show-closeWhether to show the close buttonbooleantrue
sizeSize of the Drawer window. When using number, it's in px; when using string, pass 'x%'; otherwise it will be interpreted as numbernumber / string
titleTitle of the Drawer. Can also be passed via named slot (see below)string
with-headerControls whether to show the header bar. Default is true. When false, both the title attribute and title slot are ineffectivebooleantrue
modal-classCustom class name of the mask layerstring
z-indexSet z-indexnumber
header-aria-levelThe aria-level attribute of the headerstring2
onOpenCallback when Drawer opensFunction
onOpenedCallback when Drawer opening animation endsFunction
onCloseCallback when Drawer closesFunction
onClosedCallback when Drawer closing animation endsFunction
Event NameDescriptionType
operate-viewView button event({ tableRef, row }) => void

Released under the MIT License.