ag-Grid & Vuex | creating a modern user widget

  |   Vuejs

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.

Updating a user record

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!

Read more posts about...