Table Component with Model-View-Presenter

Lars Gyrup Brink Nielsen
3 min readJan 16, 2019

Hi Ganea, thank you for your kind words 😊

In this diagram, I have modeled an example of the different classes we could have in a use case like that.

A table component with Model-View-Presenter

Some Service for retrieving and sending data, for example by GET and POST HTTP requests. A TableContainerComponent that retrieves data from the service, probably using some Observable. A presentational TableComponent which could have an *ngFor directive iterating over the data and rendering a RowComponent for each entry.

Each row component could have one or more presenters. In the diagram, I have added a single presenter per row component with a class named RowPresenter. I would probably additionally have another presenter per row component for handling form controls and validation, called RowForm for lack of a specific data type. If we were editing heroes, I would call the presenter class HeroForm.

The user edits a field in the browser, which triggers a native input event. The presentational row component delegates to the row presenter (or form presenter). Maybe the user has to press a save button.

If the form is valid, a Subject emits an object representing the submitted form — a simple data structure, not an NgForm or FormGroup.The presentational row component is notified of the emitted value and itself emits it through an output property — an EventEmitter.

The presentational TableComponent gets notified in a method, it could for example be called onFormSave or onRowSave if the output property is named save. The presentational table component simply emits the submitted form object through its own output property.

Finally, the TableContainerComponent is notified of the value emitted from TableComponent and delegates to the service. The service sends for example a POST HTTP request to the back-end which updates the data.

At some point, we detect the state change and, the observable emits a new array of entries, and the table row text is updated. Or if the server state update failed, we could notify the user and roll back the row text.

This is a pretty shallow component tree, so the bucket-brigading (or prop drilling) of emitted value from output to event handler to output is not too bad. If we had a presentational component per cell and a lot of different columns, things could start to become messy and tedious.

In that case, we could choose to create a TableService whose only purpose is to communicate between the table container component and the row/cell components. However, to use a service other than a presenter (all injectable dependencies fall under the Angular umbrella term service), we would have to introduce a row/cell container component since presentational components should only communicate with the rest of the app through input and output properties.

Adding a container component to a <tr>, <td> , or <th> might simply not be structurally possible with regards to the HTML. In this case, we can replace the row/cell container component with a provider directive.

For details on provider directives, see slides from my talk “Model-View-Presenter with Angular”. I will write an article about them at some point.

--

--