Our Comments
component will hold the list of all the comments, and its view will create a Comment
component for each comment in that list. Each Comment
component will use an Editor
component to provide in-place editing of its content. These editors work autonomously using their own controls, and they emit an event if the content is changed or altered in any way. To take care of this, we need to re-emit this event with the name commentEdited
from the Comment
component. Now we only need to catch this event within our Comments
component in order to update the list of comments with the changes. This is illustrated in the following part of the code:
onCommentEdited(comment, content) { const comments = this.comments.slice(); if (content.length === 0) { comments.splice(comments.indexOf(comment), 1); } else { comments.splice(comments.indexOf(comment), 1, { user: comment.user, time: comment.time, content }); } this.commentsUpdated.next(comments); }
This method will be called for each individual Comment
component that is repeated using the NgFor
directive. From the view, we pass a reference to the comment object concerned, as well as the edited content we would receive from the Comment
component event.
The comment object will only be used to determine the position of the updated comment within the comment list. If the new comment content is empty, we will remove the comment from the list. Otherwise, we will just create a copy of the previous comment object, change the content with the new edited content, and replace the old comment object in the list with the copy.
Finally, since we wanted to communicate the change in the comment list, we emitted an event using the commentUpdated
output property.
With this, we have completed our commenting system, and now it’s time to make use of it. We already have an empty tab prepared for our project comments, and this is going to be the spot where we will add commenting capabilities using our commenting system.
First, let’s amend our Project
component template, project/project.html
, to include the commenting system:
... <ngc-tabs> <ngc-tab name="Tasks">...</ngc-tab> <ngc-tab name="Comments"> <ngc-comments [comments]="comments" (commentsUpdated)="updateComments($event)"> </ngc-comments> </ngc-tab> <ngc-tab name="Activities"></ngc-tab> </ngc-tabs>
This is as easy as it gets. Since we are paying attention to a clean component architecture, the inclusion of our commenting system really works like a breeze. The only thing we now need to ensure is that we provide a property on our project with a list of comments. We also need a way to react to changes if comments are updated within our Comments
component. For this purpose, we will create an updateComments
method.
Let’s look at the component class changes within the project/project.js
file:
export class Project { ... @Input() comments; ... updateComments(comments) { this.projectUpdated.next({ comments }); } }
Since we are already dealing with project updates in a general way and our Project
component is emitting directly to our App
component, where projects data will be persisted, the only thing we need to implement is an additional input property, as well as a method to handle comment updates
Recap
Within this Tutorial , we have successfully created a full-fledged commenting system that can be placed in various areas of our application to enable commenting. Users can interact with in-place editors to edit the content in comments, which gives them a great user experience.
While writing the code for our commenting system, we learned about the following topics:
- Implementing a simple pipe using the
@Pipe
annotation and theMoment.js
library to provide relative time formatting - Using the
OnChanges
life cycle hook to prevent unwanted or invalid values within input properties - Using
@ViewChild
to obtain a reference to the components within the component sub-tree in order to establish direct communication - Reusing the
Editor
component as an input field replacement and as an autonomous in-place editor within theComment
component