Provide Plugin for Grids (table with editable cells)

Parse – DatagridBvue

v1.0.0

Provide Plugin for Grids (table with editable cells). And also components for filtering. This plugin use BootstrapVue.

For displaying tabular data, supports pagination, filtering, sorting, various style options, events, and asynchronous data.

  • Vue.js v2.7.14 is recommended

  • Bootstrap-vue is 2.23.1 recommended

  • Bootstrap is 4.6.0 recommended

Features

Available components:

Available features:

  • Pagination
  • Filtering
  • Sorting
  • Customizable
  • Asynchronous data
  • Custom field types
  • Custom rules components
  • Rules schemas
  • Customizable style
  • i18n translation (en, fr)

Installation

yarn add yarn add https://github.com/newera-systems/parse-vue-datagrid-engine.git#datagrid-bvue

// Import Bootstrap and BootstrapVue CSS files (order is important)
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'
import 'bootstrap-vue/dist/bootstrap-vue-icons.min.css'

import DataGridPlugin from 'DataGridBvue'
Vue.use(DataGridPlugin, {
  ruleSchemas: {
    Student: [
      {identifier: 'id', name: 'id', type: 'String'},
      {identifier: 'firstName', name: 'Prenom', type: 'String'},
      {identifier: 'lastName', name: 'Nom', type: 'String'},
    ],
  },
})

can be initialised with custom field type viewers and editors

import CustomTypeViewer from './CustomFieldViewer.vue'
import CustomTypeEditor from './CustomEditor.vue'

Vue.use(DataGridPlugin, {
  lang: 'Fr', //default Fr
  calendarTime: false, //default true
  dateFormat: 'ddd DD-MM-YY HH:mm',
  customFieldTypes: [
    {name: 'SomeType', viewer: CustomTypeViewer, editor: CustomTypeEditor},
  ],
})

can be used with rules schema

Rules schemas allows you to use the Filter component.

Vue.use(DataGridPlugin, {
  lang: 'fr',
  ruleSchemas: {
    Student: [
      {identifier: 'id', name: 'id', type: 'String'},
      {identifier: 'firstName', name: 'Prenom', type: 'String'},
      {identifier: 'lastName', name: 'Nom', type: 'String'},
    ],
  },
})

The Filter component inject inside your provider ctx object a FilterRuleInterface Object.

Usage

can add an “#action” as a field to use

<template #action="{item, index}">
  action slot
  {{ index }} {{ item }}
</template>

// add an extra field to use in the action slot
const fields = {
  identifier: '#action',
  name: 'Actions',
  config: {
    canView: true,
    canRead: true,
    canEdit: false,
    canFilter: true,
    canSort: true,
  },
  type: FieldType.String,
}

Datagrid Table

Complete Example can be found in the dev folder.

Extra (provider function, fields type autodetect and pagination)

  • Autodetect fields type with correct edition component in the cell
  • Extra slot for actions
  • Provider for async data and Database connection
    • Generated pagination, can be also used with provider function by adding paginationEntries
      paginationEntries // number of total entries for pagination using provider function

<template>
  <div>
    <h1>{{ title }}</h1>
    <DataGridTable
      name="school"
      :items="provider"
      @goToEditor="goToItemEditor"
    />
  </div>
</template>

<script lang="ts">
import Vue from 'vue'

export default Vue.extend({
  data() {
    return {
      title: 'Testing datagrid',
      items: [
        {
          id: 'Rebellious66',
          age: 53,
          first_name: 'Dragon',
          last_name: 'Monkey D.',
          da: new Date(),
          skills: [],
        },
      ],
    }
  },
  methods: {
    async provider(ctx) {
      //ctx
      return this.items
    },
    goToItemEditor(item) {
      const msg = 'open complete editor for item, ' + JSON.stringify(item)
      alert(msg)
    },
  },
})
</script>
  • Modification handler

<template>
  <div>
    <h1>{{ title }}</h1>
    <DataGridTable
      name="valhalla"
      :items="provider"
      @goToEditor="goToItemEditor"
      @modified="modificationStart"
      :modification-handler="modificationHandler"
    />
  </div>
</template>

<script lang="ts">
import Vue from 'vue'

export default Vue.extend({
  data() {
    return {
      title: 'Testing datagrid',
      items: [
        {
          id: 'Rebellious66',
          age: 40,
          first_name: 'Ragnar',
          last_name: 'Lothbrok',
          da: new Date(),
          skills: [],
        },
      ],
    }
  },
  computed: {},
  methods: {
    // will call this function after each modification handler routine
    async provider(ctx) {
      // use ctx for api calls
      const delay = (ms) => new Promise((res) => setTimeout(res, ms))
      await delay(2000)
      return this.items
    },
    // can be used to prepare a route to edit page
    goToItemEditor(item) {
      const msg = 'open complete editor for item, ' + JSON.stringify(item)
      alert(msg)
    },
    // you can use a custom modification handler
    async modificationHandler({item, field_key, newValue}) {
      item[field_key] = newValue
    },
    modificationStart() {
      // a call to the modification handler was emitted
      console.log('modified')
    },
  },
  watch: {},
})
</script>
  • Other fields

<template>
  <div>
    <h1>{{ title }}</h1>
    <DataGridTable name="school" :items="items" :fields="fields" striped />
  </div>
</template>

<script lang="ts">
import Vue from 'vue'
import {Money} from 'ts-money/build'

export default Vue.extend({
  data() {
    return {
      title: 'Testing page',
      items: [
        {
          id: 'aaa',
          a: 'hello_0',
          b: 'Fr',
          c: 10,
          d: 'M',
          e: null,
          f: new Money(1200, 'CAD'),
          g: [],
        },
        {
          id: 'bbb',
          a: undefined,
          b: 'fr',
          c: 78,
          d: '',
          e: {className: 'Invoice'},
          f: 89,
          g: [],
        },
        {id: 'ccc', h: '', i: 'QC', j: null},
      ],
      fields: [
        {
          identifier: 'id',
          name: 'Id title',
          config: {
            canView: true,
            canRead: true,
            canEdit: false,
            canFilter: true,
            canSort: true,
          },
          type: 'String',
        },
        {
          identifier: 'a',
          name: 'message',
          config: {
            canView: true,
            canRead: true,
            canEdit: false,
            canFilter: true,
            canSort: true,
          },
          type: 'String',
        },
        {
          identifier: 'b',
          name: 'Language',
          config: {
            isVisible: true,
            isWritable: true,
            showFilter: false,
            showInGrid: true,
            sortable: false,
          },
          type: 'Lang',
        },
        {
          identifier: 'c',
          name: 'Percent',
          config: {
            canView: true,
            canRead: true,
            canEdit: false,
            canFilter: true,
            canSort: true,
          },
          type: 'Percent',
        },
        {
          identifier: 'd',
          name: 'Gender',
          config: {
            canView: true,
            canRead: true,
            canEdit: false,
            canFilter: true,
            canSort: true,
          },
          type: 'Gender',
        },
        {
          identifier: 'e',
          name: 'Other',
          config: {
            canView: true,
            canRead: true,
            canEdit: false,
            canFilter: true,
            canSort: true,
          },
          type: 'Pointer',
          onClickExternalRoutine: this.testPointerHandler,
        },
        {
          identifier: 'f',
          name: 'Account',
          config: {
            canView: true,
            canRead: true,
            canEdit: false,
            canFilter: true,
            canSort: true,
          },
          type: 'Money',
        },
        {
          identifier: 'g',
          name: 'Courses',
          config: {
            canView: true,
            canRead: true,
            canEdit: false,
            canFilter: true,
            canSort: true,
          },
          type: 'Array',
        },
      ],
    }
  },
  methods: {
    async provider(ctx) {
      // const delay = ms => new Promise(res => setTimeout(res, ms));
      // await delay(3000)
      return this.items
    },
    async testPointerHandler(data) {
      // can be used to start move the page or notify an attempt to modify a pointer type
      console.log(data)
    },
  },
})
</script>

A usa as Table

B-Table style props available:

Name Types
striped Boolean
bordered Boolean
borderless Boolean
outlined Boolean
small Boolean
hover Boolean
dark Boolean
fixed Boolean
footClone Boolean
headVariant String
noCollapse Boolean
responsive Boolean

<template>
  <div>
    <h1>{{ title }}</h1>
    <DataGridTable
      name="school"
      :items="items"
      :fields="fields"
      @goToEditor="goToItemEditor"
    />
  </div>
</template>

<script lang="ts">
import Vue from 'vue'

export default Vue.extend({
  data() {
    return {
      title: 'Testing datagrid',
      items: [
        {id: 'aaa', a: 1, b: 2, c: 3},
        {id: 'bbb', a: 4, b: 5, c: 6},
        {id: 'ccc', a: 7, b: 8, c: 9},
      ],
      fields: [
        {
          identifier: 'id',
          name: 'Id title',
          type: 'String',
        },
        {
          identifier: 'a',
          name: 'A',
          type: 'String',
        },
        {
          identifier: 'b',
          name: 'b',
          type: 'String',
        },
      ],
    }
  },
  methods: {
    goToItemEditor(item) {
      const msg = 'open complete editor for item, ' + JSON.stringify(item)
      alert(msg)
    },
  },
})
</script>

Rule Engine Filter

To use the filter you need to add the target name that matches the schema name

//index.ts

Vue.use(DataGridPlugin, {
  ruleSchemas: {
    Student: [
      {identifier: 'id', name: 'id', type: 'String'},
      {identifier: 'firstName', name: 'Prenom', type: 'String'},
    ],
  },
})

//App.vue

<DataGridTable
  name="42 School"
  target="Student"
  :items="provider"
  :fields="fields"
/>
  • You can also use the filter as a standalone component

<RuleEngineFilter
  v-model="filterBuild"
  :field-list="authorisedFields"
  operator="AND"
  target="Student"
  visible-name="School"
/>

Modal Rule Creator

<template>
  <div class="my-4">
    <h2>{{ title }}</h2>
    <div class="d-inline-flex">
      <button class="btn btn-primary ml-4" @click="toggleModal">
        Toggle Modal
      </button>
      <button
        class="btn btn-primary ml-4"
        @click="
          () => {
            useEditor = !useEditor
          }
        "
      >
        Toggle custom editor
      </button>
    </div>
    <RuleEngineCreatorModal
      ref="mod"
      v-model="modalVisible"
      :use-editor="useEditor"
      :rule="filterBuild"
      target="Invoice"
      @edited="
        (filterEdited) => {
          filterBuild = filterEdited
        }
      "
    >
      <template v-slot:editor="{value, onEditorInput}">
        <div class="form-group">
          <label for="">Custom editor</label>
          <input
            type="text"
            class="form-control"
            :value="value"
            @input="(val) => onEditorInput(val.target.value)"
          />
        </div>
      </template>
    </RuleEngineCreatorModal>
  </div>
</template>

<script lang="ts">
import Vue from 'vue'

export default Vue.extend({
  data() {
    return {
      title: 'Rule Creation Modal Tester',
      filterBuild: null,
      modalVisible: false,
      useEditor: false,
    }
  },
  methods: {
    toggleModal() {
      this.$refs.mod.toggleModal()
    },
  },
})
</script>

Development

  • Vite for development
  yarn dev
  • ts-jest for testing
  yarn test

GitHub

View Github