2.2.1 • Published 3 years ago

vuejs-spreadsheet v2.2.1

Weekly downloads
77
License
MIT
Repository
github
Last release
3 years ago

:fire: Vue Spreadsheet 2.2.1 :fire:

https://github.com/joffreyBerrier/vue-spreadsheet/releases/tag/2.2.1

Medium article (in french)

https://medium.com/scalia/vuejs-spreadsheet-692cab2cb5c8

Medium article for publish your own component on npm

https://medium.com/js-dojo/how-to-publish-a-vuejs-component-on-npm-aa703714b512

Sandbox example

Open this link on a new tab

Edit vuejs-spreadsheet

Description

:facepunch: An easier Spreadsheet in Vue.js :facepunch:

Do not hesitate to :star: my repo

Project setup

yarn add vuejs-spreadsheet

npm i vuejs-spreadsheet
<script>
  import VueTable from 'vuejs-spreadsheet';
  export default {
    name: 'app',
    data() {
    },
    components: {
      VueTable,
    },
  };
</script>

Contributing to development

  • First, fork the repo from github.
  • Clone your forked repo and run: yarn or npm i
  • You can use the /example folder to test out the component, or use npm link to another project (cf. next sub section).
  • Then, make your changes on any branch you want and push it.
  • Naming your branch with the gitflow convention:
  • Finally, open a pull request on the official repo, using the source branch from your forked repo.

Debugging and testing from another project

If you want to link the local project to another project 'B' with access to the sources, follow these intructions:

  • go to the root of this project's folder
  • update the package.json to point to the source entry point instead of the dist/ main: 'src/index.js'
  • run npm link (or yarn link).
  • go to the project you import the library
  • run npm link vuejs-spreadsheet
  • Now, in your node_modules, the vuejs-spreadsheet dependencies should be a symlink to this local folder!

In order to make it work, you make change your webpack's configuration by using:

config: {
  resolve: {
    symlinks: true,
  }
}

This will enable your project's B to compile this library using the babel / webpack configuration here, as if it was a real compiled node_module.

(This configuration may depend on your webpack builder)

Wiki :mortar_board:

Data bindingTypeDescription
v-modelArrayThat contains data
PropsTypeDescription
:headersArrayThat contains headers
:custom-optionsObjectThat contains Options
:style-wrap-vue-tableObjectThat contains style of the wrapper tableVue
:disable-cellsArrayThat contains the headerKey you want to disable
:disable-sort-theadArrayThat contains the disabled th
:loadingBooleanTrue => Hidden TbodyData / show slot loaderfalse => contrary
:parent-scroll-elementObjectThat contains the HTML attribute which overflow-y: scroll (by-default is 'html')
:select-positionObjectThat contains a top and left position you want to add to the select
:submenu-tbodyArrayThat contains the submenu-tbody
:submenu-theadArrayThat contains the submenu-thead
OptionsTypeDescription
:fuse-optionsObjectThat contains an object of fuse configuration look on her website: http://fusejs.io/
:new-dataObjectThat contains the type of data when you have empty cell in a row
:sort-headerBooleanThat activates sort button on header
:tbody-indexBooleanThat displays the index of each row on the left of the table
:tradObjectThat contains an object of translating
FunctionTypeDescription
@tbody-all-checked-rowFunctionFired when the checkedAll row has checked
@tbody-checked-rowFunctionFired when row has checked
@tbody-change-dataFunctionFired when data undergo modifications
@tbody-input-changeFunctionWhen the input changes
@tbody-input-keydownFunctionTrigger keydown when the input changes
@tbody-select-changeFunctionWhen the select change
@handle-up-drag-size-headerFunctionFired when the header size changed
@thead-td-sortFunctionWhen you press the button sort
@tbody-undo-dataFunctionWhen you hit Ctrl / Cmd + Z for undo
@tbody-paste-dataFunctionWhen you paste data to a cell
@tbody-up-dragtofillFunctionFired when pressed up on dragToFill
@tbody-move-dragtofillFunctionFired when moved on dragToFill
@tbody-nav-backspaceFunctionWhen you press backspace on cell (event, actualElement, actualCol, rowIndex, colIndex)
@tbody-nav-multiple-backspaceFunctionFired when the multiple cell are delete
@tbody-submenu-click-{#}Function{#} - Name of the function declared on submenu-tbody

Example

  <vue-table
    v-model="Array"
    :headers="Array"
    :custom-options="Object"
    :style-wrap-vue-table="Object"
    :disable-cells="Array"
    :disable-sort-thead="Array"
    :loading="Boolean"
    :parent-scroll-element="Object"
    :select-position="Object"
    :submenu-tbody="Array"
    :submenu-thead="Array"
    @tbody-checked-row="checkedData"
    @tbody-all-checked-row="checkedAllData"
    @tbody-change-data="changeData"
    @tbody-undo-data="undoData"
    @tbody-submenu-click-change-color="changeColorTbody"
    @tbody-submenu-click-change-value="changeValueTbody"
    @thead-submenu-click-change-color="changeColorThead"
    @thead-submenu-click-change-value="changeValueThead"
    @thead-td-sort="sortProduct">

    // if your want to add an specific header
    <div slot="header">
      Specific Header
    </div>

    // if your want to add a loader
    <div slot="loader">
      Loader
    </div>
  </vue-table>

Options :honeybee:

  customOptions: {
    dragToFill: true,
    tbodyCheckbox: false,
    tbodyIndex: true,
    sortHeader: true,
    trad: {
      lang: 'fr',
      en: {
        select: {
          placeholder: 'Search by typing',
        },
      },
      fr: {
        select: {
          placeholder: 'Taper pour chercher',
        },
      },
    },
    newData: {
      type: 'input',
      value: '',
      active: false,
      style: {
        color: '#000',
      },
    },
    fuseOptions: {
      shouldSort: true,
      threshold: 0.2,
      location: 0,
      distance: 30,
      maxPatternLength: 64,
      minMatchCharLength: 1,
      findAllMatches: false,
      tokenize: false,
      keys: [
        'value',
      ],
    },
  },

Comment Box :triangular_ruler:

If you want to use the commentBox (like excel)

Create an object comment: {} on styleWrapVueTable and on each data

:exclamation: You can choose a global BorderColor for each commentBox

Example

  styleWrapVueTable: {
    ...
    comment: {
      borderColor: '#696969',
      borderSize: '8px',
      widthBox: '120px',
      heightBox: '80px',
    },
  },

:exclamation: Or specific color for each commentBox

CommentBox without content:

  f: {
    ...
    comment: {
      borderColor: '#eee',
    },
    ...
  },

CommentBox with content:

  f: {
    ...
    comment: {
      value: 'comment',
      borderColor: '#eee',
    },
    ...
  },

Checkbox :white_check_mark:

If you want to use the checkbox

1: Create a key tbodyCheckbox: true on customOptions

If you want to get the array of the checked data use this.$refs.vueTable.checkedRows

Example

  customOptions: {
    ...
    tbodyCheckbox: boolean
    ...
  },

Headers :tiger:

NameTypeDescription
headerNameStringThe chosen header name
headerkeyStringThe Slugify version of the headerName
styleObjectThe style of the td
- widthStringIndicate the width of <th>
- minWidthStringminWidth must be equal to width
disabledBooleanoptional - Disabled cell

Example

headers: [
  {
    headerName: 'Image',
    headerKey: 'img',
    style: {
      width: '100px'
      minWidth: '100px'
    },
  },
  {
    headerName: 'Nom',
    headerKey: 'name',
    style: {
      width: '100px'
      minWidth: '100px'
    },
  },
  {
    headerName: 'Prénom',
    headerKey: 'surname',
    style: {
      width: '100px'
      minWidth: '100px'
    },
  },
  {
    headerName: 'Age',
    headerKey: 'age',
    style: {
      width: '100px'
      minWidth: '100px'
    },
  },
  {
    headerName: 'Born',
    headerKey: 'born',
    style: {
      width: '100px'
      minWidth: '100px'
    },
  },
],

Data :honeybee:

NameTypeDescription
keyStringThe key of the object written in Slugify
typeStringThe type of data rendered (<textarea>, <img>, <select>)
value(img/input)StringThe value of the object in String Type
value(select)ArrayThe value of the object in Array Type
selectOptionsArrayThat contains objects {value: ~, label: ~}
styleObjectThe Style of the cell
activeBooleanOf the cell, false by default
handleSearchBoolean- Activates search when selected
disabledBooleanoptional - Disabled cell
numericBooleanoptional - Restrict input to numeric value

Example

products: [
  {
    img: {
      type: 'img',
      value: 'https://via.placeholder.com/350x150',
      active: false,
      disabled: true,
    },
    name: {
      type: 'input',
      value: 'John',
      active: false,
      style: {
        color: '#000',
      },
    },
    surname: {
      type: 'input',
      value: 'Doe',
      active: false,
      style: {
        color: '#000',
      },
    },
    age: {
      type: 'select',
      handleSearch: true,
      selectOptions: [
        {
          value: 'paris',
          label: 'Paris',
        },
        {
          value: 'new-york',
          label: 'New York',
        },
      ],
      value: 'paris',
      active: false,
    },
    born: {
      type: 'select',
      handleSearch: true,
      selectOptions: [
        {
          value: 'france',
          label: 'France',
        },
        {
          value: 'usa',
          label: 'United States of America',
        },
      ],
      value: 'france',
      active: false,
    },
  },
],

New Data :tiger:

Example

Same Object describe on the top

If you choose an input

newData: {
  type: 'input',
  value: '',
  active: false,
  style: {
    color: '#000',
    background: '#cfffcf',
  },
},

submenu :monkey_face:

NameTypeDescription
typeStringThe type of data rendered (<button><select>)
valueStringThe value of the function
functionStringThe name of the function called when you click on the button - Written in Slugify
disabledArrayEach object which you want to hide on the submenu
subtitleStringOf the select
selectOptionsArrayThat contains objects {value: ~, label: ~}
buttonOptionObjectDescription
. valueStringThe value of the button
. functionStringThe name of the function called when you click on the button - Written in Slugify
. styleObjectThe style of the button

Example

  submenuTbody: [
    {
      type: 'button',
      value: 'Change Color',
      function: 'change-color',
      disabled: ['img'],
    },
  ],
  submenuThead: [
    {
      type: 'button',
      value: 'Change Color',
      function: 'change-color',
      disabled: ['img', 'name'],
    },
    {
      type: 'select',
      disabled: ['img'],
      subtitle: 'Select state:',
      selectOptions: [
        {
          value: 'new-york',
          label: 'new-york',
        },
        {
          value: 'france',
          label: 'france',
        },
      ],
      value: 'new-york',
      buttonOption: {
        value: 'change city',
        function: 'change-city',
        style: {
          display: 'block',
        },
      },
    },
  ],

Example :mortar_board: :tiger:

<template>
  <div id="app">
    <vue-table
      v-model="products"
      :headers="headers"
      :custom-options="customOptions"
      :style-wrap-vue-table="styleWrapVueTable"
      :disable-cells="disableCells"
      :disable-sort-thead="disableSortThead"
      :loading="loading"
      :parent-scroll-element="parentScrollElement"
      :select-position="selectPosition"
      :submenu-tbody="submenuTbody"
      :submenu-thead="submenuThead"
      @tbody-change-data="changeData"
      @tbody-submenu-click-change-color="changeColorTbody"
      @tbody-submenu-click-change-value="changeValueTbody"
      @thead-submenu-click-change-color="changeColorThead"
      @thead-submenu-click-change-value="changeValueThead"
      @thead-td-sort="sortProduct">
    <div slot="header">
      Specific Header
    </div>
    <div slot="loader">
      Loader
    </div>
    </vue-table>
  </div>
</template>

<script>

import VueTable from 'vuejs-spreadsheet';

export default {
  name: 'app',
  data() {
    return {
      customOptions: {
        tbodyIndex: true,
        sortHeader: true,
        trad: {
          lang: 'fr',
          en: {
            select: {
              placeholder: 'Search by typing',
            },
          },
          fr: {
            select: {
              placeholder: 'Taper pour chercher',
            },
          },
        },
        newData: {
          type: 'input',
          value: '',
          active: false,
          style: {
            color: '#000',
          },
        },
        fuseOptions: {
          shouldSort: true,
          threshold: 0.2,
          location: 0,
          distance: 30,
          maxPatternLength: 64,
          minMatchCharLength: 1,
          findAllMatches: false,
          tokenize: false,
          keys: [
            'value',
          ],
        },
      },
      submenuTbody: [
        {
          type: 'button',
          value: 'change color',
          function: 'change-color',
          disabled: ['img'],
        },
        {
          type: 'button',
          value: 'change value',
          function: 'change-value',
          disabled: ['img', 'name'],
        },
      ],
      submenuThead: [
        {
          type: 'button',
          value: 'change color',
          function: 'change-color',
          disabled: ['a'],
        },
        {
          type: 'select',
          disabled: ['a'],
          subtitle: 'Select state:',
          selectOptions: [
            {
              value: 'new-york',
              label: 'new-york',
            },
            {
              value: 'france',
              label: 'france',
            },
          ],
          value: 'new-york',
          buttonOption: {
            value: 'change city',
            function: 'change-city',
            style: {
              display: 'block',
            },
          },
        },
        {
          type: 'button',
          value: 'change value',
          function: 'change-value',
          disabled: ['a', 'b'],
        },
      ],
      disableCells: ['a'],
      loading: false,
      parentScrollElement: {
        attribute: 'html',
        positionTop: 0,
      },
      selectPosition: {
        top: 0,
        left: 0,
      },
      disableSortThead: ['a'],
      styleWrapVueTable: {
        fontSize: '12px',
        comment: {
          borderColor: '#696969',
          borderSize: '8px',
          widthBox: '120px',
          heightBox: '80px',
        },
      },
      headers: [
        {
          headerName: 'A',
          headerKey: 'a',
          style: {
            width: '200px',
            minWidth: '200px',
            color: '#000',
          },
        },
        {
          headerName: 'B',
          headerKey: 'b',
          style: {
            width: '200px',
            minWidth: '200px',
            color: '#000',
          },
        },
        {
          headerName: 'C',
          headerKey: 'c',
          style: {
            width: '200px',
            minWidth: '200px',
            color: '#000',
          },
        },
        {
          headerName: 'D',
          headerKey: 'd',
          style: {
            width: '200px',
            minWidth: '200px',
            color: '#000',
          },
        },
        {
          headerName: 'E',
          headerKey: 'e',
          style: {
            width: '200px',
            minWidth: '200px',
            color: '#000',
          },
        },
        {
          headerName: 'F',
          headerKey: 'f',
          style: {
            width: '200px',
            minWidth: '200px',
            color: '#000',
          },
        },
        {
          headerName: 'G',
          headerKey: 'g',
          style: {
            width: '200px',
            minWidth: '200px',
            color: '#000',
          },
        },
      ],
      products: [
        {
          a: {
            type: 'img',
            value: 'https://via.placeholder.com/350x150',
            active: false,
          },
          c: {
            type: 'input',
            value: 'Paris',
            active: false,
            style: {
              color: '#000',
            },
          },
          d: {
            type: 'input',
            value: 'France',
            active: false,
            style: {
              color: '#000',
            },
          },
          e: {
            type: 'input',
            value: 'Boe',
            active: false,
            style: {
              color: '#000',
            },
          },
          f: {
            type: 'select',
            handleSearch: true,
            selectOptions: [
              {
                value: 'Harry Potter',
                label: 'harry potter',
              },
              {
                value: 'Hermione Granger',
                label: 'hermione granger',
              },
              {
                value: 'Ron Whisley',
                label: 'ron whisley',
              },
              {
                value: 'Dobby',
                label: 'dobby',
              },
              {
                value: 'Hagrid',
                label: 'hagrid',
              },
              {
                value: 'Professeur Rogue',
                label: 'professeur rogue',
              },
              {
                value: 'Professeur Mcgonagal',
                label: 'professeur mcgonagal',
              },
              {
                value: 'Professeur Dumbledor',
                label: 'professeur dumbledor',
              },
            ],
            value: 'professeur dumbledor',
            active: false,
          },
          g: {
            type: 'select',
            handleSearch: true,
            selectOptions: [
              {
                value: 1980,
                label: 1980,
              },
              {
                value: 1981,
                label: 1981,
              },
              {
                value: 1982,
                label: 1982,
              },
              {
                value: 1983,
                label: 1983,
                active: true,
              },
              {
                value: 1984,
                label: 1984,
              },
            ],
            value: 1983,
            active: false,
          },
        },
      ],
    };
  },
  components: {
    VueTable,
  },
  mounted() {
    this.loading = true;
    setTimeout(() => {
      this.loading = false;
    }, 300);
  },
  methods: {
    changeData(row, header) {
      console.log(row, header);
    },
    sortProduct(event, header, colIndex) {
      console.log('sort product');
    },
    // callback
    changeColorThead(event, header, colIndex) {
      this.headers[colIndex].style.color = '#e40000';
    },
    changeColorTbody(event, header, rowIndex, colIndex) {
      this.products[rowIndex][header].style = {};
      this.products[rowIndex][header].style.color = '#e40000';
    },
    changeValueTbody(event, header, rowIndex, colIndex) {
      this.products[rowIndex][header].value = 'T-shirt';
    },
    changeValueThead(event, entry, colIndex) {
      this.headers[colIndex].headerName = 'T-shirt';
    },
  },
};
</script>

<style lang="scss">
::-moz-selection {
  color: #2c3e50;
  background: transparent;
}
::selection {
  color: #2c3e50;
  background: transparent;
}
</style>

LICENSE

MIT

2.2.1

3 years ago

2.2.0

3 years ago

2.1.7

4 years ago

2.1.6

4 years ago

2.1.5

4 years ago

2.1.0

4 years ago

2.0.2

4 years ago

2.0.1

4 years ago

2.0.0

4 years ago

1.9.2

4 years ago

1.9.1

4 years ago

1.9.0

5 years ago

1.8.9

5 years ago

1.8.8

5 years ago

1.8.7

5 years ago

1.8.6

5 years ago

1.8.5

5 years ago

1.8.4

5 years ago

1.8.3

5 years ago

1.8.2

5 years ago

1.8.1

5 years ago

1.8.0

5 years ago

1.7.9

5 years ago

1.7.8

5 years ago

1.7.7

5 years ago

1.7.6

5 years ago

1.7.5

5 years ago

1.7.4

5 years ago

1.7.3

5 years ago

1.7.2

5 years ago

1.7.0

5 years ago

1.6.9

5 years ago

1.6.8

5 years ago

1.6.7

5 years ago

1.6.6

5 years ago

1.6.5

5 years ago

1.6.4

5 years ago

1.6.3

5 years ago

1.6.2

5 years ago

1.6.1

5 years ago

1.6.0

5 years ago

1.5.9

5 years ago

1.5.8

5 years ago

1.5.6

5 years ago

1.5.5

5 years ago

1.5.4

5 years ago

1.5.3

5 years ago

1.5.2

5 years ago

1.5.1

5 years ago

1.5.0

5 years ago

1.4.5

5 years ago

1.4.4

5 years ago

1.4.3

5 years ago

1.4.2

5 years ago

1.4.1

5 years ago

1.4.0

5 years ago

1.3.8

5 years ago

1.3.7

5 years ago

1.3.6

5 years ago

1.3.5

5 years ago

1.3.4

5 years ago

1.3.3

5 years ago

1.3.2

5 years ago

1.3.1

5 years ago

1.3.0

5 years ago

1.2.9

5 years ago