A highly customisable CRUD component using VueJS and Vuetify

aaron
codeburst
Published in
8 min readJan 8, 2018

--

Article updated 2019 July 24, 1150 +8GMT

Latest release v0.2.6 (on 2019 Nov 21) Uses Vuetify 2. Please refer to This Article for v0.2 (our v0.1 refactored, improved and simplified).

This article is reserved for v0.1 updates.

The component is currently being used in production and will be continually improved based on user feedback.

There are many web-based CRUD components and applications available from the open-source community. So why build another one? Well, I would like to have a component where I can quickly build customizable admin dashboards to handle real-life use cases and vue-crud-x was created based on this need.

Other than the usual pagination, sorting and simple filters and forms, below are a few unique features and design philosophies that makes vue-crud-x stand out from the others:

  • New! SSR, Generated Static Pages & Social Login Examples
  • Able to do nested CRUD operations, for example selecting a post from a list of posts, and then selecting a comment from a list of comments of the selected post to edit
  • Auto-generate Form & Search from JSON data
  • Customizable table UI, search filters, form layout, validation
  • Handling of authentication tokens, user information, permissions
  • Use direct call (e.g. Firestore), or API (REST, GraphQL) to one or more types of datastore (MySQL, MongoDB, Redis, ElasticSearch, etc.)
  • Pagination, search, sort, inline edit, (cache, optimistic response, refetch query on Apollo GraphQL client)
  • Export to CSV, File/Image Upload, i18n
  • Multiple CRUD working on a single page
  • Social Login, Nuxt SSR and generated
  • lit-element web-component example (https://medium.zenika.com/using-lit-element-with-vue-js-fa873df4f2a4)
CRUD mixed with other components

Design Philosophy

  • Able to build an admin dashboard quickly using the component
  • Easy to maintain with as little boilerplate code as possible
  • Flexibility to handle as many use cases as possible

Drawbacks

  • The price to pay for the flexibility is the need for additional coding work for the customized layouts and crud operations by the developer.

This may look like a step backward, but if a custom layout or data operation is required, you will need to write the code anyway.

Getting Started

We will do a quick walk through how-to get a demo running on your local machine using the example-rest project. You may need to get up to speed on the following topics:

  • VueJS, Vue-router and Vuex
  • Vuetify
  • NodeJS, ES6, async-await, ExpressJS
  1. Change to the example-rest directory
  2. Run the following commands
npm i
npm run build-rest
npm run init-db
npm run start

View the web application on http://127.0.0.1:8080, you will see the following:

Login Screen (Google Authenticator 2FA not enabled)

Login using “test” as the username and password, click on menu icon on top left and select Books, you will see the page as shown below.

CRUD Table, Sorting & Pagination, Export

Clicking on the magnifying glass icon on the top right will open the search filter as shown below.

CRUD table filters
CRUD Form (“VIEW BOOK PAGES” Button opens next level in a nested CRUD use-case, you can have more buttons opening to other child items related to this selected item)

Inline Edit Mode

When in inline edit mode, CRUD functions can be done within the table view. However, you are not able do nested CRUD when using inline edit

Inline edit - with action buttons on the left

Some Important Notes To Be Aware Of

Currently “id” field is required as a unique identifier and needs to be defined in your datastore. Allowing this field to be user-defined will be done in future if possible.

Customization Code Walk-through

The code snippet below is from example-rest/src/pages/Book.vue

It shows how to use vue-crud-x and customise the search filters and forms using scoped-slots, and props.

It is also a parent table in a nested CRUD use-case, where 1 book (parent) has many pages (child).

The v-autocomplete part shows how to implement a production grade autocomplete feature with rxJs, which includes debounce, and taking only latest query.

Selecting and unselecting autocomplete items show how to relate and unrelate items in a many-to-many relation (M-N).

scoped-slots

  • slot=”filter” is where you customise the search filter
  • slot=”form” is where you customise the form. In our nested crud use-case, there is a gotoPages() method which shows how to navigate to the pages (child table) of a selected book
  • slot =”table” is where you can replace the table with your own UI component

props

  • storeName holds the name of Vuex store module the vue-crud-x component will use
  • parentId if not null means there is a parent table to the vue-crud-x component
  • ref allows your component to access the vue-crud-x component
  • @form-open listens to a “form-open” event from the crud component and allows you to write code that acts on it
  • bookDefs is the data object with the properties to setup and configure the vue-crud-x component. The main properties are crudTable, crudFilter and crudForm, crudOps, and they are explained below

crudOps

This contains the crud operations for the vue-crud-x component, available actions are export(), find(), findOne(), update(), create(), delete().

crudFilter

This contains the fields that will be filtered and the UI component used for each filter

crudForm

This contains the fields for the input form, the properties should match or be a subset of what is read from the findOne() operation

crudTable

Configuration for the vue-crud-x component table, headers, inline edits, confirmations, styling, etc.

Child Table, Inline Edit & Export Walk-through

The code snippet below is from example-rest/src/pages/Page.vue

It shows how the implement child table of a nested CRUD and CSV/JSON export, as well as configuration for inline edit.

In our case this component list the pages (child) of a selected book (parent)

The parentId passed in, indicates that this is a child table.

The property pageDefs.crudTable.showGoBack is set to true, to indicate that you want a button to go back to the parent table. You can also implement your own code which will call this.$router.back().

// INLINE EDIT - START and // INLINE EDIT - END shows the parts of code to configure inline editing.

The function pageDefs.crudOps.export(), shows how to export data to CSV/JSON

Projects In The Repository

There are example 4 projects in this repository which illustrate complete use-cases including the backend.

The projects are listed below and indicate any additional examples of supporting technologies such as Server-side rendering, reactive programming, etc.

example-rest

  • rxJS, autocomplete
  • Web-sockets
  • 2FA using Google Authenticator
  • GraphQL

example-firebase

  • Google Firebase, Firestore, Authentication, Recaptcha
  • Webcam image capture and upload to cloud storage
  • Use and interaction of multiple vue-crud-x components in a single page

example-nuxt

  • Server-side rendering (SSR)
  • Generated Static Pages
  • Social Login

backend

  • objectionJS (ORM), Sqlite, mongoDB, GraphQL
  • Key-value store (& Redis)
  • OpenAPI
  • Social Login

Final Words

I hope that you will find this article useful, vue-crud-x is continually improved and contributors are welcome to help make it better and address more production use-cases.

If there are any features that I may have missed out, you can raise an issue on Github.

Should you have any questions you can reach out via email or on telegram @aaronjxz, if they cannot be resolved here.

Thank you for reading this rather long article and happy coding!

Supplementary Article - Setup For “example” Project

Below are additional setup information to help get the example project, which uses Firebase as a backend, to run.

Signing Up For Firebase

  1. Create a new google account or use an existing google account
  2. Goto Google Firebase and signup for firebase, you may need to enter your credit card information to access their services
  3. Create a user (https://firebase.google.com/docs/auth/web/password-auth), you will need this user to log in to the example program
  4. Enable your firestore and enable read-write in the rules
Create a dummy user in Firebase Authentication
Enable read-write rules (unsecure rules, use only for test purpose)

Get Your Credentials

See picture below on where to get your firebase credentials

Click on “Add Firebase to your web app”, the big round icon button in the middle right that turns red when you hover or it, to reveal you credentials

Your credentials should look like the JSON below…

<script src="https://www.gstatic.com/firebasejs/4.13.0/firebase.js"></script>
<script>
// Initialize Firebase
var config = {
apiKey: "...",
authDomain: "...",
databaseURL: "...",
projectId: "...",
storageBucket: "...",
messagingSenderId: "..."
};
firebase.initializeApp(config);
</script>

Use the information in var config, save it in a file called cfg.json

Create Firestore Collections

  1. party Collection and sample Document

2. note Collection and sample Document

Relationship

One party (e.g. a party to a lawsuit) can have zero or more notes (e.g. case notes)
One note belongs to only one party

The parent Key for the note Collection sample document shown above is “party” and relates to the “name” field in the party Collection document

Create Indexes

See picture below on the indexes to create for the note collection.

Google Recaptcha

If you want to use Recaptcha in the login process, you can sign up for your own Recaptcha site-key from Google Recaptcha.

NOTE: Recaptcha is bypassed when the client detects the host serving the page is 127.0.0.1 or localhost, so you do not need Recaptcha site-key in development environment.

File Upload (this documentation is work-in-progess)

The ImageUpload.vue component can now be added to a crud form to upload images to Firebase storage and save its path to an existing record.

Check your firebase storage for the image after clicking upload button.

--

--