In this article I will explain a simple approach I took in one of my projects that required me to develop a dynamic table where users can read and modify fields. The challenge was that there is no set of defined tables or data models from the back-end. At any time, a new data model can be created or removed from the database and the front-end is required to adapt without having to add/remove tables manually.
So from the very beginning I decided to go with an abstract approach solution to make the table model dynamic and schema agnostic. For example, if one of the columns in the data model changed from ‘number’ to ‘date’ type then the table will respond dynamically and populate a date input field instead of a number field.
To achieve this we need couple of things from the data source (or back-end APIs):
- A list of data (duh!):
2. Data schema:
When the UI table consumes the data list and schema, we will get the following results:
As you can see in the above video, editing a row will change the field to a text input. Now let’s add a new date column ‘dateOfBirth’ with a ‘date’ type and change the ‘age’ schema to ‘number’ type:
The end results will look like this:
As demonstrated in the above video, and without any changes to the code, the same table was able to dynamically display the proper input field type based on the schema provided.
The actual implementation is not complex at all, so let’s get right into it and show you how it’s done! The repository is available at the very end of the article.
- Setup an Angular app with Material UI
- Create a simple read-only Material table
- Create a dynamic table using a data schema
- Add edit row functionality
- Support more complex data types
1. Setup an Angular app with Material UI:
ng new angular-dynamic-table
ng add @angular/material
2. Create a simple read-only Material table:
In the app.component.ts file we will add a ‘USER_INFO’ data as a JSON variable (this typically comes from the back-end) with the required properties for the Material table component.
Then, in the app.component.html file we will add the required columns and display the list from the dataSource property (USER_INFO).
3. Create a dynamic table using a data schema:
Now that we have the basic table working, let’s start adding dynamic input fields based on the data schema. For now, we will replace text fields with HTML input elements but in the next section we will add an edit functionality to toggle between read-only and edit mode.
The first step is to loop through the columns and display them dynamically instead of hard coding each one.
The second step is to add the data schema to define each column type. In this example it will be ‘USER_SCHEMA’.
The last step is to add an HTML input field with dynamic ‘type’ attribute. We are going to use Material input field.
As you can see above (line 11), we added a Material input field with a dynamic ‘type’. The ‘type’ is determined by the ‘dataSchema’ object we defined earlier (USER_SCHEMA). Using the ‘col’ key we can easily get the input type (text, number, date..). Then, the HTML input will know which one to display as these types are all built in.
4. Add edit row functionality:
In a real life scenario the user would want to have a read-only mode by default and then edit a row when required.
To achieve this, we first need to add an edit button for each row. This will require us to add a new column in the ‘displayColumns’ list. Let’s name it ‘$$edit’ so that we can distinguish between the internal props and the actual data.
Then let’s add a condition in the template to toggle between read-only and edit mode.
- In line 6 we are hiding the ‘$$edit’ column name as we don’t need it showing on the table’s header.
- Line 11 and 19 controls which section to show based on the ‘isEdit’ value which by default will be ‘undefined’ (or false).
- In line 13 and 21, the button element will toggle the ‘isEdit’ prop and hence automatically adding it to the element’s object.
5. Support for more complex data types:
What we just implemented supports basic html types such as input number, text…
One approach to supporting more complex types can be by simply adding new conditions in the Angular template. For example, let’s assume we want to add the Material date element instead of the HTML built in one. To do so we can add a conditional block to check if the data type is ‘date’ otherwise use the default code we did earlier.
Same thing can be applied to any custom component.
You can access the full repository here. I hope you enjoyed learning from this article and if you have any questions, please leave a comment below.
Originally published at https://muhimasri.com on July 28, 2020.