{"id":25416309,"url":"https://github.com/uwla/vue-data-table","last_synced_at":"2025-04-07T08:16:21.964Z","repository":{"id":38272034,"uuid":"242402881","full_name":"uwla/vue-data-table","owner":"uwla","description":"Vue plugin that adds advanced features to an HTML table.","archived":false,"fork":false,"pushed_at":"2024-05-11T19:20:53.000Z","size":4179,"stargazers_count":128,"open_issues_count":8,"forks_count":22,"subscribers_count":3,"default_branch":"vue3","last_synced_at":"2024-05-11T20:26:28.694Z","etag":null,"topics":["data-table","vue","vue2","vue3"],"latest_commit_sha":null,"homepage":"https://uwla.github.io/vue-data-table/demo","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/uwla.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-02-22T19:56:20.000Z","updated_at":"2024-05-30T00:19:48.693Z","dependencies_parsed_at":"2023-12-17T20:42:54.795Z","dependency_job_id":"c798ad99-03c8-42ae-bbe0-f6992f9ac448","html_url":"https://github.com/uwla/vue-data-table","commit_stats":null,"previous_names":["andresouzaabreu/vue-data-table"],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uwla%2Fvue-data-table","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uwla%2Fvue-data-table/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uwla%2Fvue-data-table/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uwla%2Fvue-data-table/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/uwla","download_url":"https://codeload.github.com/uwla/vue-data-table/tar.gz/refs/heads/vue3","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247615382,"owners_count":20967184,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["data-table","vue","vue2","vue3"],"created_at":"2025-02-16T16:30:58.348Z","updated_at":"2025-04-07T08:16:21.917Z","avatar_url":"https://github.com/uwla.png","language":"TypeScript","readme":"# VUE DATA TABLE\n\n`VueDataTable` is a Vue plugin to easily create fully-featured data tables.\n\n\u003c!-- vim-markdown-toc GFM --\u003e\n\n* [FEATURES](#features)\n* [DEMO](#demo)\n* [GETTING STARTED](#getting-started)\n    * [Installation](#installation)\n    * [Set up](#set-up)\n    * [Usage](#usage)\n    * [Nuxt integration](#nuxt-integration)\n    * [Laravel integration](#laravel-integration)\n* [CONFIGURATION](#configuration)\n    * [Columns](#columns)\n        * [Custom Cell Component](#custom-cell-component)\n        * [Action Buttons](#action-buttons)\n        * [Editable cells](#editable-cells)\n        * [Selectable rows](#selectable-rows)\n    * [Text](#text)\n        * [Adding Language](#adding-language)\n    * [Async data](#async-data)\n    * [Layout](#layout)\n    * [Custom Components](#custom-components)\n        * [Footer](#footer)\n        * [Sort Icon](#sort-icon)\n        * [Sorting Index Icon](#sorting-index-icon)\n* [ROADMAP](#roadmap)\n* [LICENSE](#license)\n* [CONTRIBUTING](#contributing)\n\n\u003c!-- vim-markdown-toc --\u003e\n\nCheck out my other plugin, [vue-form-builder](https://github.com/uwla/vue-form-builder),\nthat automatically generates beautiful forms from declarative rules.\n\n## FEATURES\n\n- Pagination\n- Search filter\n- Single column sorting\n- Multiple column sorting\n- Customize every visible text\n- Support for multiple languages\n- Export data (JSON, CVS, TXT or XLS)\n- Action buttons (view, edit, delete)\n- Editable cells (edit cell values)\n- Custom Vue components to render cells\n- Custom Footer to display data summary\n- Support for Vue3 and Vue2\n- Nuxt integration\n- Laravel integration\n\n## DEMO\n\nThe best way to see if a package suits your needs is by viewing and testing  its\nfunctionalities via a [demo app](https://uwla.github.io/vue-data-table/demo).\n\nThere is also this [CodeSandbox Playground](https://codesandbox.io/s/vue3-data-table-demo-c7kfj5)\nin which you can edit the source code with live preview.\n\n![Vue Data Table Demo 1](./assets/vdt-1.png)\n![Vue Data Table Demo 2](./assets/vdt-2.png)\n![Vue Data Table Demo 3](./assets/vdt-3.png)\n\n## GETTING STARTED\n\n### Installation\n\n```shell\nnpm install @uwlajs/vue-data-table\n```\n\nMake sure to install version `2.0.0` or above for Vue3.\n\nVersions prior to `2.0.0` are for Vue2. Checkout the `vue2` branch for its documentation.\n\n### Set up\n\n```javascript\nimport VueDataTable from \"@uwlajs/vue-data-table\";\nVue.component(\"vue-data-table\", VueDataTable);\n```\n\nDon\"t forget to add the style sheets\n\n```javascript\nimport \"@uwlajs/vue-data-table/dist/VueDataTable.css\";\n```\n\n### Usage\n\n```vue\n\u003ctemplate\u003e\n    \u003cdiv\u003e\n        \u003cdata-table v-bind=\"bindings\"/\u003e\n    \u003c/div\u003e\n\u003c/template\u003e\n\u003cscript\u003e\nexport default {\n    computed: {\n        bindings() {\n            return {\n                columns: [/*the columns*/]\n                data: [/*the data*/]\n                /* other props...*/\n            }\n        }\n    },\n}\n\u003c/script\u003e\n```\n\n**Note** Notice that v-bind will take all key-value pairs in the object (in this\ncase, the `bindings`), and pass them as props to the `VueDataTable.` So, this is\na shortcut to pass multiple props at once.\n\n### Nuxt integration\n\nCreate a file `@/plugins/vue-data-table.js`, or whatever name you wish, with the following content:\n\n```javascript\nimport VueDataTable from '@uwlajs/vue-data-table'\nimport '@uwlajs/vue-data-table/dist/style.css'\n\nexport default defineNuxtPlugin(nuxtApp =\u003e {\n  nuxtApp.vueApp.use(VueDataTable)\n})\n```\n\nNuxt automatically loads the files in the `plugins/` directory by default.\n\n### Laravel integration\n\nThis plugin integrates  with  Laravel's  pagination  API,  so  it  fetches  data\nasynchronously  from  the  provided  URL. Follow the instrunctions in the\n[async data section](#async-data) for a detailed setup.\n\n## CONFIGURATION\n\nOnly `columns` are required. Other props are optional.\n\nIf `data` is not passed, then `fetchUrl` and `fetchCallback` *must* be passed.\n\n`vKey` is not required but is **highly** recommend to set it if you plan to\nadd or delete rows in the table!\n\n| prop                  | type               | default                           | description                                                                                |\n| --------------------- | ------------------ | --------------------------------- | ------------------------------------------------------------------------------------------ |\n| allowedExports        | `Array`            | `[\"csv\", \"json\", \"txt\"]`          | Formats the user can export the data to. Allowed values: `csv`, `json`, `txt`, `xlsx`      |\n| data                  | `Array`            | -                                 | Array of objects with the data to be displayed on the table                                |\n| columns               | `Array`            | -                                 | Array of objects to specify how to render each column. Optional if `columnKeys` is set     |\n| columnKeys            | `Array`            | -                                 | Array of strings matching the object keys in `data`. Discarded if `columns` is set         |\n| lang                  | `String`           | `en`                              | The default language                                                                       |\n| perPageSizes          | `Array`            | [10, 25, 50, 100, '*']            | The options for the number of rows being displayed per page. The string '*' shows all.     |\n| defaultPerPage        | `Number`           | 10                                | The default number of entries. If unset, then it will be the first value of `perPageSizes` |\n| fetchUrl              | `String`           | -                                 | The URL to fetch data from if `data` is null                                               |\n| fetchCallback         | `String`           | -                                 | Async function which takes an URL and returns `data` matching Laravel's pagination API     |\n| isLoading             | `Bool`             | `false`                           | Whether table data is loading. Table rows are shown only if this value is set to `false`   |\n| loadingComponent      | `String`, `Object` | -                                 | VueJS component to be shown if `isLoading` is set to `true`                                |\n| showPerPage           | `Bool`             | `true`                            | Whether to show the `PerPage` component                                                    |\n| showEntriesInfo       | `Bool`             | `true`                            | Whether to show the `EntriesInfo` component                                                |\n| showSearchFilter      | `Bool`             | `true`                            | Whether to show the `SearchFilter` component                                               |\n| showPagination        | `Bool`             | `true`                            | Whether to show the `Pagination` component                                                 |\n| showDownloadButton    | `Bool`             | `true`                            | Whether to show the button to download the table's data                                    |\n| tableClass            | `String`           | `table table-striped table-hover` | The table's HTML `class` attribute                                                         |\n| sortingMode           | `String`           | `multiple`                        | Whether to sort a single column or multiple columns at once                                |\n| sortingIndexComponent | `String`, `Object` | `VdtSortingIndex`                 | VueJS component for the sorting index on sortable columns                                  |\n| sortingIconComponent  | `String`, `Object` | `VdtSortingIcon`                  | VueJS component for the sorting icon on sortable columns                                   |\n| footerComponent       | `String`, `Object` | `null`                            | VueJS component for custom table footer                                                    |\n| vKey                  | `String`           | -                                 | The `v-key`, the key in `data` used by Vue to track and distinguish array elements.        |\n\n### Columns\n\n| key             | type               | default          | description                                               |\n| --------------- | ------------------ | ---------------- | --------------------------------------------------------- |\n| key             | `String`           | -                | The object field to be displayed in a table cell          |\n| title           | `String`           | `titleCase(key)` | The title displayed in the header                         |\n| searchable      | `Bool`             | `true`           | Whether to allow searching rows by this column field      |\n| sortable        | `Bool`             | `true`           | Whether to allow sorting the data by this column field    |\n| editable        | `Bool`             | `true`           | Whether the column is editable by the user                |\n| collapsible     | `Bool`             | `false`          | Whether the column is collapsible (expand and collapse)   |\n| type            | `String`           | `string`         | Data type of `key`. Allowed values: `string`, `number`    |\n| compareFunction | `Function`         | -                | Custom function provided by the user to sort the column   |\n| searchFunction  | `Function`         | -                | Custom function provided by the user to search the column |\n| index           | `Number`           | 1000             | Lower values shift the column to the left of the table    |\n| component       | `String`, `Object` | -                | Custom Vue component to render inside table cell          |\n| componentProps  | `Object`           | -                | Props to pass to the custom component                     |\n\nIf `columns` is not defined, then `columnKeys` must be defined and  it  will  be\nmapped to a `columns` array with the default parameters. Example:\n\n```javascript\n// we can define the columns\nconfig = {\n    data: users,\n    columns: [\n        {\n            key: \"name\",\n        },\n        {\n            key: \"email\",\n            title: \"Email Address\",\n            sortable: false,\n        },\n        {\n            key: \"phone\",\n            sortable: false,\n            searchable: false,\n            index: 1, // smaller indexes means the column is shift to the left\n        },\n        {\n            key: \"permissions\",\n\n            /* custom function sort users by which user has more permissions */\n            compareFunction: function(a, b) {\n                // permissions is an array\n                return a.permissions.length - b.permissions.length;\n            },\n\n            /* custom function to allow searching the permission array */\n            searchFunction: function(search, data) {\n                return data.permissions.some(permission =\u003e permission.includes(search))\n            },\n\n            searchable: true,\n\n            /* custom component to display the permissions */\n            component: UserPermissionList,\n        }\n    ]\n}\n\n// or use columnKeys shortcut\nconfig = {\n    data: user,\n    columnKeys: [\"name\", \"email\", \"registered_at\", \"last_access_at\"]\n},\n\n// which will take the default column and map the array into this\n[\n    {\n        key: \"name\",\n        title: \"Name\",\n        sortable: true,\n        searchable: true,\n        index: 1000\n    },\n    {\n        key: \"email\",\n        title: \"Email\",\n        sortable: true,\n        searchable: true,\n        index: 1000\n    },\n    {\n        key: \"registered_at\",\n        title: \"Registered At\",\n        sortable: true,\n        searchable: true,\n        index: 1000\n    },\n    {\n        key: \"last_access_at\",\n        title: \"Last Access At\",\n        sortable: true,\n        searchable: true,\n        index: 1000\n    },\n]\n```\n\n#### Custom Cell Component\n\nCustom cell components must have a `data` property to receive the data of the current\nrow for the component to display it.\n\nIn the previous code snippet, we used our custom component `UserPermissionList`.\nBelow is a sample of that custom component.\n\n```vue\n\u003ctemplate\u003e\n    \u003cdiv\u003e\n        List of permissions for the user {{ data.name }} :\n        \u003cul\u003e\n            \u003cli v-for=\"(permission, i) in data.permissions\" :key=\"i\"\u003e\n                {{ permission }}\n            \u003c/li\u003e\n        \u003c/ul\u003e\n    \u003c/div\u003e\n\u003c/template\u003e\n\u003cscript\u003e\nexport default {\n    name: \"UserPermissionList\",\n    props: {\n        data: {\n            type: Object,\n            required: true\n        }\n    }\n}\n\u003c/script\u003e\n```\n\nTo handle events triggered by a custom component (such as clicking a button in a\ncomponent), the component should emit an event called `userEvent`  and  pass  an\narbitrary payload to it. The event will be propagated upwards by `VueDataTable`,\nwhich will also emit an event called `userEvent` whose payload is  the  same  as\nthe one emitted by the custom component. For example:\n\n```vue\n\u003ctemplate\u003e\n    \u003cinput type=\"checkbox\" class=\"form-control\" :checked=\"value\" @change='toggleChecked' /\u003e\n\u003c/template\u003e\n\u003cscript\u003e\nexport {\n    name: 'CheckboxCell',\n    data() {\n        return {\n            value: false,\n        }\n    },\n    methods: {\n        toggleChecked() {\n            const payload = {\n                id: this.data.id,\n                checked: this.value,\n            }\n            this.$emit('userEvent', payload)\n        }\n    },\n    props: {\n        data: Object,\n    }\n}\n\u003c/script\u003e\n```\n\nWhen the users clicks the checkbox, it will emit an `userEvent` event, which can\nbe accessed from the `VueDataTable`. Here is an  continuation  of  the  previous\nexample.\n\n```vue\n\u003ctemplate\u003e\n    \u003cdiv class=\"dashboard\"\u003e\n        \u003ch1\u003eDASHBOARD\u003c/h1\u003e\n        \u003cbutton class=\"btn btn-danger\"\u003e\n            DELETE SELECTED ROWS\n        \u003c/button\u003e\n        \u003cvue-data-table\n            :data=\"data\"\n            :columns=\"columns\"\n            @userEvent=\"handleEvent\" /\u003e\n    \u003c/div\u003e\n\u003c/template\u003e\n\u003cscript\u003e\nexport default {\n    data() {\n        return {\n            data: [/**/],\n            columns: [/**/],\n            selectedRows: [],\n        }\n    },\n    methods: {\n        handleEvent(payload) {\n            const { checked, id } = payload\n            if (checked === true) {\n                if (! this.selectedRows.includes(id))\n                    this.selectedRows.push(id)\n            } else {\n                this.selectedRows = this.selectedRows.filter(rowId =\u003e rowId !== id)\n            }\n        },\n        deleteRows() {\n            this.data = this.data.filter(row =\u003e ! this.selectedRows.includes(row.id))\n            this.selectedRows = []\n        }\n    }\n}\n\u003c/script\u003e\n```\n\nIn the code snippet above, when the user checks the  checkbox  rendered  by  the\ncustom component `CheckboxCell`, it will emit an event that is  handled  by  the\nmethod `handleEvent`. This method will add/remove the `id` of  the  row  to/from\nthe `selectedRows` array. When the user clicks the \"dangerous delete button\", it\nwill deleted the selected rows from the table (on the client side only).\n\n#### Action Buttons\n\n`VueDataTable` provides a component called `VdtActionButtons`, which can be used\nto display buttons for common CRUD action such as viewing, editing, deleting.\n\nHere is an example with all buttons (view, edit, delete) in one column:\n\n```vue\n\u003ctemplate\u003e\n    \u003cmain\u003e\n        \u003ch1\u003eDASHBOARD\u003c/h1\u003e\n        \u003cvue-data-table v-bind=\"params\" @userEvent=\"handleUserEvent\"/\u003e\n    \u003c/main\u003e\n\u003c/template\u003e\n\u003cscript\u003e\nimport { VdtActionButtons } from '@uwlajs/vue-data-table'\nexport default {\n    data() {\n        return {\n            params: {\n                data: users,\n                columns: [\n                    { key: 'name' },\n                    { key: 'job' },\n                    { component: VdtActionButtons, title: \"actions\" },\n                ],\n            },\n        }\n    },\n    methods: {\n        handleUserEvent(payload) {\n            console.log(payload.action, payload.data.name)\n        }\n    }\n}\n\u003c/script\u003e\n```\n\nAnother example, this time one button per column:\n\n```vue\n\u003ctemplate\u003e\n    \u003cmain\u003e\n        \u003ch1\u003eDASHBOARD\u003c/h1\u003e\n        \u003cvue-data-table v-bind=\"params\" @userEvent=\"handleUserEvent\"/\u003e\n    \u003c/main\u003e\n\u003c/template\u003e\n\u003cscript\u003e\nimport { VdtActionButtons } from '@uwlajs/vue-data-table'\nexport default {\n    data() {\n        return {\n            params: {\n                data: users,\n                columns: [\n                    { key: 'name' },\n                    { key: 'job' },\n                    {\n                        title: \"view\"\n                        component: VdtActionButtons,\n                        componentProps: { actions: [\"view\"] },\n                    },\n                    {\n                        title: \"edit\"\n                        component: VdtActionButtons,\n                        componentProps: { actions: [\"edit\"] },\n                    },\n                    {\n                        title: \"delete\"\n                        component: VdtActionButtons,\n                        componentProps: { actions: [\"delete\"] },\n                    },\n                ],\n            },\n        }\n    },\n    methods: {\n        handleUserEvent(payload) {\n            console.log(payload.action, payload.data.name)\n        }\n    }\n}\n\u003c/script\u003e\n```\n\nWhen an user click an action button, `VueDataTable` will  emit  an  event  whose\npayload is an object with two fields: `action` and `data`. The `action`  is  the\nname of the action (view, edit, delete) and `data` is the data of the row.\n\nCheck out the demo to see a real working example of using action buttons.\n\n#### Editable cells\n\nIt is possible to make a column editable by settings `editable` to true in the\ncolumn definition.\n\n```javascript\ncolumns: {\n    [ 'key': name, editable: true],\n    [ 'key': email, editable: true],\n    [ 'key': phone, editable: true],\n    // ...\n}\n```\n\nThis will make `VueDataTable` display an `edit` button on the right side of  the\ncell's text. When the user clicks the button, it will show an input, so the user\ncan enter a new value for the cell. The user can cancel the editing or  confirm.\nIf the user confirms editing,  `VueDataTable`  will  emit  a  `userEvent`  whose\npayload looks like the following:\n\n```javascript\n{\n    action: 'updateCell',\n    key: '\u003ckey String\u003e',\n    data: '\u003cdata Object\u003e',\n    value: '\u003cvalue String\u003e',\n}\n```\n\nWhere `key` is the key of the column (if user edits the `name` column, the `key`\nwill be `name`), the `data` is the object of the row which was edit (an example:\n`{ id: 100, name: 'joe', email: 'joe@email.test' }`), and `value` is  the  value\ninserted by the user (such as `Joe Doe`).\n\nIt is up to the developer to handle the event to update the row by, for example,\nsending an AJAX request to the API, then updating the `data` array on the client\nside. Here is an example of how to update the data array on the client side:\n\n```vue\n\u003ctemplate\u003e\n  \u003cvue-data-table :data=\"data\" :columns=\"columns\" @userEvent=\"handleUserEvent\"/\u003e\n\u003c/template\u003e\n\u003cscript\u003e\nexport default {\n    /* ... */\n\n    methods: {\n        handleUserEvent(payload) {\n            if (payload.action === 'updateCell')\n            {\n                // send some ajax request\n                // ...\n\n                // then update the cell\n                this.updateDataCell(payload.data, payload.key, payload.value)\n\n            } else {\n                // some other event\n            }\n        },\n        updateDataCell(row, field, value) {\n            let ind = this.data.findIndex(r =\u003e r.id === row.id)\n            if (ind \u003c 0) return\n            let newRow = {... this.data[ind]}\n            newRow[field] = value\n            this.data.splice(ind, 1, newRow)\n        },\n    }\n}\n\u003c/script\u003e\n```\n\n#### Selectable rows\n\n`VueDataTable` provides the built-in `vdt-cell-selectable` component to select\ntable rows.\n\n```javascript\nconst props = {\n    columns = [\n        {\n            title: \"\",\n            component: \"vdt-cell-selectable\" // \u003c-- ADD THIS\n        },\n        { key: \"name\" },\n        { key: \"email\" },\n        /* ... */\n    ],\n    vKey = \"id\",\n};\nconst data = [\n    { id: 1, name: \"joe\", email: \"joe@example.com\" },\n    /* ... */\n]\n```\n\nWhen the user toggles the checkbox, `VueDataTable` emits an event called\n`userEvent` with the following payload:\n\n```javascript\n{\n    action: \"select\",\n    selected: true || false, // this is the current value of the checkbox\n    data: {}, // this is the current row (example, a user from an users array)\n}\n```\n\nYou can have a reactive variable to keep track of selected items:\n\n```javascript\nconst selected = ref([]);\n\nconst handleSelect(payload) {\n    const item = payload.data;\n    if (payload.selected) {\n        selected.value.push(item);\n    } else {\n        selected.value = selected.value.filter((x) =\u003e x.id !== item.id);\n    }\n}\n```\n\nYou can use this variable to perform bulk operations, such as mass deletion or\nmass edition.\n\n### Text\n\nCurrently, `VueDataTable` has support for the following languages: English (en),\nBrazilian Portuguese (pt-br), and Spanish(es).  The  `lang`  prop  specifies  in\nwhich language to display the text in our table.\n\nIf we want to add a custom text (maybe because there is no language  support  or\nbecause we want something else), we have to set it in the `text` prop.\n\nThe following table shows the texts we can customize and  their  default  values\nfor the English language.\n\n| key                        | default                                                               |\n| ---                        | ---                                                                   |\n| perPageText                | \"Show :entries entries\"                                               |\n| perPageAllText             | \"ALL\"                                               |\n| infoText                   | \"Showing :first to :last of :total entries\"                           |\n| infoAllText                | \"Showing all entries\"                           |\n| infoFilteredText           | \"Showing :first to :last of :filtered (filtered from :total entries)\" |\n| nextButtonText             | \"Next\"                                                                |\n| previousButtonText         | \"Previous\"                                                            |\n| paginationSearchText       | \"Go to page\"                                                          |\n| paginationSearchButtonText | \"GO\"                                                                  |\n| searchText                 | \"search:\"                                                             |\n| downloadText               | \"export as:\"                                                          |\n| downloadButtonText         | \"DOWNLOAD\"                                                            |\n| emptyTableText             | \"No matching records found\"                                           |\n\n**Note**:  Notice  that  the  placeholders  `:first`,  `:last`,  `:total`,   and\n`:filtered` will be automatically replaced with the proper numbers.\n\nExample code:\n\n```javascript\nparameters() {\n    return {\n        data: [/**/],\n        columns: [/**/],\n        text: {\n            PerPageText: \"Number of users per page :entries\",\n            infoText: \"Displaying :first to :last of :total users\",\n            emptyTableText: \"No users found :(\",\n        }\n    }\n}\n```\n\n#### Adding Language\n\nIf your language is not yet supported, you can add a new language and use it  in\nany `VueDataTable` instance as follow:\n\n```javascript\nimport { languageServiceProvider } from \"@uwlajs/vue-data-table\";\n\nconst loremIpsumLanguage = {\n    perPageText: \"lorem ipsum\",\n    nextButtonText: \"labore ipsum\",\n    /* more ... */\n};\n\nlanguageServiceProvider.setLang(\"lorem\", loremIpsumLanguage)\n```\n\nYou can also change any default text for an  existing  language  and  that  will\nreflect the changes globally. For example:\n\n```javascript\n// the default text for the download button in the export component is \"export as\"\n// we may want change that to \"download as\"\nlanguageServiceProvider.setLangText(\"en\", \"downloadText\", \"download as:\")\n```\n\n\n### Async data\n\nIf you do not want to fetch all data at once and pass it to `VueDataTable` via\nthe `data` prop, you can do so by defining:\n\n- `fetchUrl`: initial endpoint for the first ajax request to fetch data\n- `fetchCallback`: async function which takes an URL and returns a response\nfollowing Laravel's pagination API.\n\nHere is a sample `fetchCallback`:\n\n```vue\n\u003ctemplate\u003e\n    \u003ch1\u003eUsers\u003c/h1\u003e\n    \u003cvue-data-table v-bind=\"vdtProps\" /\u003e\n\u003c/template\u003e\n\u003cscript setup\u003e\nconst vdtProps = {\n    columns: [\n        { key: 'name' },\n        { key: \"email\", title: \"Email address\" },\n    ],\n    fetchUrl: \"http://app.test/api/users\",\n    fetchCallback: async (url) =\u003e fetch(url).then(response =\u003e response.json())\n}\n\u003c/script\u003e\n```\n\nThe example above uses the browser's built-in `fetch`, but you can also use\n`axios` or Nuxt's `$fetch` under the hood. Just make sure the response returned\nby the callback matches the following.\n\nThe response from the `fetchCallback` should look like this:\n\n```jsonc\n{\n  \"data\": [\n    { \"id\": 1, \"name\": \"Miss Juliet Heidenreich\", \"email\": \"alvera13@example.org\"},\n    { \"id\": 2, \"name\": \"Heloise Boehm\", \"email\": \"joany.feil@example.net\"},\n    { \"id\": 3, \"name\": \"Antwon Collins\", \"email\": \"xhills@example.com},\n    /* ... */\n  ],\n  \"current_page\": 1,\n  \"first_page_url\": \"http://app.test/api/users?page=1\",\n  \"from\": 1,\n  \"last_page\": 23,\n  \"last_page_url\": \"http://app.test/api/users?page=23\",\n  \"links\": [\n    { \"url\": null, \"label\": \"\u0026laquo; Previous\", \"active\": false },\n    { \"url\": \"http://app.test/api/users?page=1\", \"label\": \"1\", \"active\": true },\n    { \"url\": \"http://app.test/api/users?page=2\", \"label\": \"2\", \"active\": false },\n    { \"url\": \"http://app.test/api/users?page=3\", \"label\": \"3\", \"active\": false },\n    /* ... */\n    { \"url\": \"http://app.test/api/users?page=23\", \"label\": \"23\", \"active\": false },\n    { \"url\": \"http://app.test/api/users?page=2\", \"label\": \"Next \u0026raquo;\", \"active\": false }\n  ],\n  \"next_page_url\": \"http://app.test/api/users?page=2\",\n  \"path\": \"http://app.test/api/users\",\n  \"per_page\": 15,\n  \"prev_page_url\": null,\n  \"to\": 15,\n  \"total\": 340\n}\n```\n\nHere is how you do so in Laravel:\n\n```php\n\u003c?php\n\nuse App\\Models\\User;\nuse Illuminate\\Support\\Facades\\Route;\n\nRoute::get('users', function () {\n    return User::paginate();\n});\n```\n\nThis will also work with collections: `new UserCollection(User::paginate())`.\n\nIn order to be able to **sort** and **search** using endpoints  compatible  with\nLaravel's API, this plugin provides support for Spatie's Laravel  Query  Builder\npackage, which allows you to easily generate  API  endpoints  with  sorting  and\nsearching functionalities with well-defined standard.\n\n```php\n\u003c?php\n\nuse App\\Models\\User;\nuse Illuminate\\Support\\Facades\\Route;\nuse Spatie\\QueryBuilder\\QueryBuilder;\n\nRoute::get('users', function () {\n    return QueryBuilder::for (User::class)\n        -\u003eallowedSorts(['name', 'email'])\n        -\u003eallowedFilters(['name', 'email'])\n        -\u003epaginate();\n});\n```\n\nThe endpoints look like this:\n\n- `http://app.test/api/users?page=1\u0026filter[name]=foo`\n- `http://app.test/api/users?page31\u0026sort=job,-email`\n- `http://app.test/api/users?page=1\u0026sort=email\u0026filter[email]=joe\u0026filter=[name]=joe`\n\nYou do **not** need to worry about the URLs if you are using Spatie's Laravel Query Bulder,\nbecause `VueDataTable` follows their endpoint standard and automatically generates the urls.\n\nIf you do not use their package, then you should parse the `url` variable inside\nthe `fetchCallback`, and modify the url. For example, your javascript code should modify:\n\n`http://app.test/api/users?page=4\u0026filter[name]=foo --\u003e http://app.test/api/users?page=4\u0026search=foo`.\n\nKeep in mind that, by default, Spatie's Query Builder apply AND logic for all\nfilters. That means if you have `\u0026filter[name]=Ana\u0026filter[email]=Ana`, then\nyou will only get results that both `name` and `email` fields match Ana. If\n`name` matches Ana but not the `email` column, then this row would not appear.\n\nHere is how you can implement `OR` logic using their package:\n\n```php\n\u003c?php\n\n// routes/app.php\nuse App\\Http\\Filters\\FilterOrWhere;\nuse App\\Models\\User;\nuse Illuminate\\Support\\Facades\\Route;\nuse Spatie\\QueryBuilder\\QueryBuilder;\nuse Spatie\\QueryBuilder\\AllowedFilter;\n\nRoute::get('users', function () {\n    return QueryBuilder::for (User::class)\n        -\u003eallowedSorts(['name', 'email'])\n        -\u003eallowedFilters([\n            AllowedFilter::custom('name', new FilterOrWhere),\n            AllowedFilter::custom('email', new FilterOrWhere)\n        ])\n        -\u003epaginate();\n});\n\n// app/Http/Filters/FilterOrWhere.php\nnamespace App\\Http\\Filters;\n\nuse Spatie\\QueryBuilder\\Filters\\Filter;\nuse Illuminate\\Database\\Eloquent\\Builder;\n\nclass FilterOrWhere implements Filter\n{\n    public function __invoke(Builder $query, $value, string $property)\n    {\n        $query-\u003eorWhere($property, 'LIKE', '%' . $value . '%');\n    }\n}\n```\n\n### Layout\n\n`VueDataTable` uses CSS's grid display to specify the position of its components\n(search filter, pagination, entries info, per page options, download button).\n\n**We can specify the position of the components by including our custom CSS/SCSS\nand overriding the defaults.**\n\nBy default, this is how `VueDataTable` displays the components:\n\n```scss\n.data-table {\n    display: grid;\n    width: 100%;\n    grid-template-columns: 25% 25% 25% 25%;\n    \u0026\u003e div {\n        margin-top: 1rem;\n        max-width: 100%;\n    }\n    \u0026 \u003e .data-table-search-filter, .data-table-pagination, .data-table-export-data {\n        margin-left: auto\n    }\n    @media (min-width: 1401px) {\n        grid-template-areas:\n            \"perPage search search search\"\n            \"table table table table\"\n            \"info pagination pagination download\";\n    }\n    @media (min-width: 1051px) AND (max-width: 1400px) {\n        grid-template-areas:\n            \"perPage search search search\"\n            \"table table table table\"\n            \"info pagination pagination pagination\"\n            \". . download download\";\n    }\n    @media (min-width: 851px) AND (max-width: 1050px) {\n        grid-template-areas:\n            \"perPage search search search\"\n            \"table table table table\"\n            \"pagination pagination pagination pagination\"\n            \"info info download download\";\n    }\n    @media (max-width: 800px) {\n        \u0026 \u003e .data-table-pagination {\n            flex-wrap: wrap;\n        }\n    }\n    @media (min-width: 651px) AND (max-width: 850px) {\n        grid-template-areas:\n            \"perPage search search search\"\n            \"table table table table\"\n            \"pagination pagination pagination pagination\"\n            \"info info info info\"\n            \"download download download download\";\n    }\n    @media (max-width: 650px) {\n        grid-template-areas:\n            \"search search search search\"\n            \"perPage perPage perPage perPage \"\n            \"table table table table\"\n            \"pagination pagination pagination pagination\"\n            \"info info info info\"\n            \"download download download download\";\n        \u0026 \u003e .data-table-per-page {\n            margin-left: auto\n        }\n    }\n}\n```\n\nFeel free to copy the styles above, modify it, and then set the position of the\ncomponents as you want.\n\n### Custom Components\n\nBesides a custom component for each column, you provide  custom  components  for\nthe table's footer, the column's `sorting  icon`  (the  icon  displayed  if  the\ncolumns is sorted), and the column's `sorting index` (the index of  the  current\ncolumn if it is being sorted and multi column sorting is enabled).\n\n#### Footer\n\nThe property `footerComponent` sets the component to render the table's  footer.\nThe component can be either the component `Object`, or a `String` equals to  the\nname of the registered component.\n\nThe `footerComponent` must be a `\u003ctfoot\u003e` HTML element  and  it  must  have  the\nproperties `data`, `dataDisplayed`, `dataFiltered`. If the  component  does  not\nspecify those properties in `props`, Vue  will  probably  think  they  are  some\ncustom HTML attribute and their values will be show as HTML attributes, which is\nreally messy.\n\nThe property `data`  correspond  to  all  data  passed  to  `VueDataTable`.  The\n`dataDisplayed` corresponds to all data that is currently visible on the  table.\nThe `dataFiltered` corresponds to all data that was filtered by a search  query.\nThese properties can be used to perform common operations  such  as  calculating\nthe sum of the values of the total rows of a certain column.\n\nSuppose we have a table that of fruits. The `data` is an array of objects  whose\nproperties are `name`, `price`, and `amount`. We can provide a custom footer  to\nshow the total amount of fruits bought and the total price.\n\nThe footer component would be something like:\n\n```vue\n\u003ctemplate\u003e\n  \u003ctfoot v-show=\"dataDisplayed.length \u003e 0\"\u003e\n    \u003ctd\u003eTotal\u003c/td\u003e\n    \u003ctd\u003e\u003c/td\u003e\n    \u003ctd\u003e{{ totalAmount }}\u003c/td\u003e\n    \u003ctd\u003e{{ totalPrice }}\u003c/td\u003e\n  \u003c/tfoot\u003e\n\u003c/template\u003e\n\u003cscript\u003e\nexport default {\n  name: \"TableFooter\",\n  computed: {\n    totalPrice() {\n      let s = 0;\n      for (let f of this.dataDisplayed)\n        s += f.price * f.amount;\n      return s;\n    },\n    totalAmount() {\n      let s = 0;\n      for (let f of this.dataDisplayed)\n        s += f.amount;\n      return s;\n    }\n  },\n  props: {\n    data: Array,\n    dataDisplayed: Array,\n    dataFiltered: Array,\n  }\n}\n\u003c/script\u003e\n```\n\nAnd we pass this component as follow:\n\n```vue\n\u003ctemplate\u003e\n    \u003cdata-table v-bind=\"tableProps\"/\u003e\n\u003c/template\u003e\n\u003cscript\u003e\nimport TableFooter from './TableFooter.vue'\n\nexport default {\n    /* ... some code */\n    data() {\n        return {\n            tableProps: {\n                columns: [ /* ... code */ ],\n                data: [ /* ... more code */ ],\n                footerComponent: TableFooter,\n            }\n        }\n    }\n}\n\u003c/script\u003e\n```\n\nAlternately, you can register the component and pass a string:\n\n```javascript\n/* early on */\nimport TableFooter from './TableFooter.vue'\nVue.component(\"table-footer\", TableFooter)\n\n/* later on */\n    footerComponent: \"table-footer\"\n```\n\n#### Sort Icon\n\nBy default, `VueDataTable` will display arrows to indicate the sorting direction\nwhen sorting a column. The `SortingIcon` component is wrapped in a `th` element.\nThe `th` element has a `data-sorting` attribute that  may  be  `asc`  or  `desc`\nonly. Based on this value, we display an  `arrow_up`  or  an  `arrow_down`  icon\nusing `CSS` rules.\n\n```vue\n\u003ctemplate\u003e\n    \u003cspan class=\"data-table-sorting-icon\"\u003e\u0026nbsp;\u003c/span\u003e\n\u003c/template\u003e\n\u003cstyle lang=\"scss\" scoped\u003e\n.data-table-sorting-icon {\n    \u0026::after {\n        content: \"\\2193\";\n    }\n    \u0026::before {\n        content: \"\\2191\";\n    }\n    \u0026::after, \u0026::before {\n        opacity: 0.5;\n    }\n    [data-sorting=\"asc\"] \u0026::before, [data-sorting=\"desc\"] \u0026::after {\n        opacity: 1;\n    }\n}\n\u003c/style\u003e\n```\n\n**Note**: Some code was omitted to keep it clean.\n\nIf we want to add our custom icons for this, then we can register our component,\nlike so:\n\n```javascript\nimport SortingIcon from \"./path/to/SortIcon.vue\";\n\nexport default {\n    computed: {\n        bindings() {\n            return {\n                SortingIconComponent: SortingIcon,\n                data: [],\n                /**/\n            };\n        }\n    }\n}\n```\n\n#### Sorting Index Icon\n\nWhen sorting multiple columns, `VueDataTable` will display an icon  with a index\nindicating which column has the priority in the sorting process.\n\n```vue\n\u003ctemplate\u003e\n    \u003cspan class=\"data-table-sort-index\"\u003e\n        {{ index }}\n    \u003c/span\u003e\n\u003c/template\u003e\n```\n\nIf we want to add our own component for this, we can register it  just  like  we\ndid before.\n\n```javascript\nimport SortingIndex from \"./path/to/SortingIndex.vue\";\n\nexport default {\n    computed: {\n        bindings() {\n            return {\n                SortingIndexComponent: SortingIndex,\n                data: [],\n                /**/\n            };\n        }\n    }\n};\n```\n\nIn our  `SortingIndex`  component,  we  must  have  a  `index`  property,  which\ncorrespondent to the index of the column in the sorting process.\n\n```javascript\nexport default {\n    name: \"SortingIndex\",\n    props: {\n        index: {\n            type: Number,\n            required: true\n        }\n    }\n};\n```\n\n## ROADMAP\n\n- [x] Support for Vue3\n- [x] Laravel integration\n- [ ] Support for SSR\n- [ ] String notation for defining columns\n\n## LICENSE\n\nMIT\n\n## CONTRIBUTING\n\nPull requests are very welcome.","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuwla%2Fvue-data-table","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fuwla%2Fvue-data-table","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuwla%2Fvue-data-table/lists"}