ag-Grid & Vuex | creating a modern user widget
State Management with Vuex
We can use Vuex for state management to help us with Data Binding, and CRUD actions: creating, deleting and updating rows.
Data Binding
Documentation: ag-Grid-Vue
The data for all the records in our application is kept in a Vuex store:
// src/store/store.js
getters: {
rowData: state => {
return state.rowData;
}
}
Rows are mapped to ag-Grid using a computed property. This allows the App component to be notified every time our store is updated.
// src/App.vue
computed: {
rowData: {
get() {
return this.$store.getters.rowData;
},
[...]
}
}
Deleting rows
Documentation: Delta Row Data, Cell Renderer
A button is rendered in the right-most column of every row that, when clicked, fires an action that removes that row from the store.
The 'deleteUser' action is dispatched, passing the row data to be removed as part of the payload.
// src/components/Actions/ActionsRenderer.vue
// template
<span class="action" @click="deleteUser">
<i class="far fa-trash-alt"></i>
</span>
// script
methods: {
deleteUser() {
let user = this.params.data;
this.$store.commit("deleteUser", { user });
},
[...]
}
The mutation handler then simply filters out the row from our store.
// src/store/store.js
deleteUser(state, { user, force = false }) {
let confirm = true;
if (!force) {
confirm = window.confirm(`Are you sure you would like to remove ${user.accountDetails.username}?`)
}
if (confirm) {
let updatedRowData = this.state.rowData.filter(row => row.id !== user.id);
state.rowData = updatedRowData;
}
}
Updating rows
Documentation: Custom Editors, Full Row Editing
Our application utilises full row editing, which allows all cells in a row to enter edit mode at the same time.
When the editing row exits edit mode (either by pressing the Enter key, or the ✔ icon), ag-Grid invokes each cell editor's getValue hook - to retrieve the updated values and update the store.
// src/components/AccountDetails/AccountDetailsEditor.vue
getValue() {
return {
...this.params.value,
username: this.username,
name: this.name,
following: this.following
};
}
// src/components/Avatar/AvatarEditor.vue
getValue() {
return this.url;
}
Adding rows
Documentation: Delta Row Data
To ensure that only one row is added at one time, each new row is considered to be a 'ghost row' until it is committed.
If a user clicks on the '+' button while a ghost row is already present, the existing 'ghost row' will be highlight and no row will be added.
// src/App.vue
addUser() {
// only allow one ghost node at a time
if (this.ghostUser) {
let ghostNode = this.getGhostNode();
this.startEditingNode(ghostNode);
} else {
this.ghostUser = createGhostUser();
this.$store.commit("addGhostUser", this.ghostUser);
}
}
// src/store/store.js
mutations: {
addGhostUser(state, user) {
state.rowData.unshift(user);
},
[...]
}
Committing newly created rows
Documentation: Grid Events
After editing, non-empty ghost nodes are committed. Empty ghost nodes are removed from the store.
The logic for handling newly edited values is handled in the onRowEditingStopped grid event.
// src/App.vue
onRowEditingStopped(params) {
let user = params.data;
if (isGhostUser(user)) {
if (isBlankUser(user)) {
// remove empty rows from our data set
this.$store.commit("deleteUser", { user, force: true });
} else {
// commit non-empty, ghost rows
this.$store.commit("commitGhostUser", user);
}
}
this.ghostUser = null;
},
Below is the mutation handler used for committing ghost nodes.
// src/store/store.js
mutations: {
commitGhostUser(state, user) {
let updatedRowData = state.rowData.map(row => ({
...row,
ghost: row.id === user.id ? false : row.ghost
}))
state.rowData = updatedRowData;
},
[...]
}
Styling: SASS variable customisation
Documentation: Customising themes
With an extensive list of customisable SASS variables. It's easy to change the look and feel of the grid.
/* src/App.vue */
/* We dont want to show the column header */
$header-height: 0px;
/* Minimalistic approach*/
$row-border-width: 0px;
$border-color: white;
/* Beautifying */
$hover-color: rgb(240, 240, 240);
$editor-background-color: inherit;
@import "../node_modules/ag-grid-community/src/styles/ag-grid.scss";
@import "../node_modules/ag-grid-community/src/styles/ag-theme-balham/sass/ag-theme-balham.scss";
What's next?
If you would like to try out ag-Grid check out our getting started guides (JS / React / Angular / Vue)
Happy coding!