Wrapping Angular Material Table: Styling it once & Drag+Drop Sorting
The development of Vendasta’s Material Styled Tables
At Vendasta, we have moved most of our legacy projects away from a previous frontend framework to Angular using Angular Material as the base for our styles. While Angular Material satisfies most of our needs for interaction, we want to have a consistent look and feel across our platform that conforms with Vendasta’s visual identity. Below is an example of Angular Material’s default style for tables:
After a slight style change, this is the table we ended up with:
With the table now styled, we could copy & paste the styles or copy the stylesheet everywhere we may need it. However, neither of these options satisfy the following requirements:
- A single place to update the style and have all the tables update their style
- A simple method for our UX/UI co-workers to update the styles
Creating a component in our Shared Library
In the end I created a component in a library that is shared between all of our frontend projects. It ended up being quite a simple component with the va-mat-table.component.html
looking like this:
You can ignore the action-bar section of the component as we will cover that later on in this article. The main thing to focus on is the ng-content
(line 4) as that is where the table is outputted. Doing it this way we can have a single va-mat-table.component.scss
which styles the table itself without limiting use of the Material Table. The component does not have any knowledge of the table, all it needs to know is that it has to render something in the ng-content
section. Using this component is very simple:
Now when the table is rendered, it is set up completely in the parent component and only uses va-mat-table
for the styles of the table.
Ability to wrap any existing or new table at Vendasta
With the way the table is created, we can wrap any existing Material table with va-mat-table
and it will automatically be styled the way we want our tables at Vendasta.
Adding in the ability to pass in anything to our tables action bar
Since we are sharing a component between all of our tables, it would be the perfect spot to add in more functionality so all the tables could possibly benefit. Remember the following line from the va-mat-table.component.html
:
This is how we are going to be able to add more functionality to the tables. Since we can tag multiple ng-content
using the select attribute (https://medium.freecodecamp.org/everything-you-need-to-know-about-ng-template-ng-content-ng-container-and-ngtemplateoutlet-4b7b51223691 if you want to read more on ng-content) we are able to do something like this:
Now anything that we pass in between <ng-container action-bar-items>
will be rendered in the <div class="action-bar">
in our va-mat-table.component.html
Adding Drag and Drop sorting to the table
A feature that is requested on many of our tables is the ability to sort and toggle the columns, so adding it as something that is available to our tables makes sense.
In our va-mat-table
component I added a new folder called actions where any shared actions between the tables will live. In that folder I created a new component called column-sorter which is a regular Angular component. Its selector looks like:
which will look for something like:
Implementing the dragging and dropping of the columns is actually quite a simple process. Using the built-in Angular CDK for the dragging and dropping and Angular Material Menu for the menu functionality gives us a solid base. The most important section in the component is the Input and Outputs:
This allows us to do [(columns)]="displayedColumns"
which supplies the initial state of the columns and emits an event when the columns are reordered/toggled. When the even it emitted it updates displayedColumns
which reorders the columns of the table. It doesn’t have to be called displayedColumns
it is just the array of strings that you passed to matHeaderRowDef
and matRowDef
(refer to https://stackblitz.com/angular/oddkdyrgdyn?file=app%2Ftable-basic-example.ts for how the variable displayedColumns
works).
Now if we add it the to action bar it would look like this:
A Live example to view of the table
If you made it this far in the article, you probably are looking for a live example. Below is a live example of what the table should look like:
Conclusion
This may not be the end-all perfect solution but it solves a need within our organization for our frontend story. Using this solution we have minimal code duplication and consistent styles across our platform!