<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: White Joe</title>
    <description>The latest articles on DEV Community by White Joe (@whitejoe).</description>
    <link>https://dev.to/whitejoe</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F886877%2Ffef3c4dc-9230-4f74-8c78-d89536e9292d.png</url>
      <title>DEV Community: White Joe</title>
      <link>https://dev.to/whitejoe</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/whitejoe"/>
    <language>en</language>
    <item>
      <title>How to add a class to just right added comment, not all of them</title>
      <dc:creator>White Joe</dc:creator>
      <pubDate>Mon, 04 Jul 2022 09:00:45 +0000</pubDate>
      <link>https://dev.to/whitejoe/how-to-add-a-class-to-just-right-added-comment-not-all-of-them-4716</link>
      <guid>https://dev.to/whitejoe/how-to-add-a-class-to-just-right-added-comment-not-all-of-them-4716</guid>
      <description>&lt;p&gt;Hello, I need to add bootstrap effect fadeInDown to a newly added comment in my comments section. It works but unfortunately it affects all of the comments when I reload the page and the effect is also added when I edit a comment. Is it possible to add this specific class only to newly created comment? not affecting the rest of comments nor the other application functionalities? I will be glad for any advice.&lt;br&gt;
These are the components I'm working on: Comment section HTML&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;h6&amp;gt;Comments: ({{commentsCount}})&amp;lt;/h6&amp;gt;
&amp;lt;app-new-comment class="d-block mt-3" [requestId]="requestId" (update)="updateComments()"&amp;gt; 
&amp;lt;/app-new-comment&amp;gt;
&amp;lt;app-comment *ngFor="let comment of comments; let i = first"
         [ngClass]="{'fadeInDown': i}"
         class="d-block mt-3 animated"
         [comment]="comment"
         (update)="updateComments()"&amp;gt;&amp;lt;/app-comment&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Comment section TS&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export class CommentSectionComponent implements OnInit, OnDestroy {

@Input() requestId: string
comments: CommentDetailsDto[]
commentsCount = 0

private subscription: Subscription

constructor(
    private commentsService: CommentsService,
    private alert: AlertService
) {
}

ngOnInit(): void {
    this.updateComments()
}

ngOnDestroy(): void {
    this.unsubscribe()
}

updateComments(): void {
    this.unsubscribe()
    this.subscription = this.commentsService.getComments(this.requestId)
        .subscribe({
            next: (comments: CommentDetailsDto[]) =&amp;gt; {
                this.comments = comments.reverse()
                this.commentsCount = this.getCommentsCount(comments)
            },
            error: (error: HttpErrorResponse) =&amp;gt; {
                this.alert.handleHttpError(error)
            }
        })
}

private getCommentsCount(comments: CommentDetailsDto[]): number {
    return comments.reduce(
        (cnt, comment) =&amp;gt; cnt + 1 + (comment.replies ? this.getCommentsCount(comment.replies) : 0),
        0
    )
}

private unsubscribe(): void {
    if (this.subscription instanceof Subscription) {
        this.subscription.unsubscribe()
    }
}

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Comment section SCSS&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@keyframes fadeInDown {
from {
    opacity: 0;
    transform: translate3d(0, -100%, 0);
}
to {
    opacity: 1;
    transform: translate3d(0, 0, 0);
}
}

.fadeInDown {
    animation-name: fadeInDown;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;New comment component HTML&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div class="d-flex"&amp;gt;
&amp;lt;app-user-image class="mr-3"&amp;gt;&amp;lt;/app-user-image&amp;gt;
&amp;lt;textarea #textArea class="d-block" placeholder="Add comment" [(ngModel)]="newComment"&amp;gt; 
 &amp;lt;/textarea&amp;gt;
 &amp;lt;/div&amp;gt;
 &amp;lt;div class="text-right mt-3"&amp;gt;
    &amp;lt;button class="btn btn-primary font-weight-bold px-5" type="button" 
 [disabled]="!newComment" (click)="submit()"&amp;gt;
       Post
     &amp;lt;/button&amp;gt;
 &amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;New comment TS&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export class NewCommentComponent implements OnInit {

@ViewChild('textArea') textArea: ElementRef&amp;lt;HTMLTextAreaElement&amp;gt;
@Input() requestId?: string
@Input() comment?: CommentDetailsDto
@Output() update = new EventEmitter()
newComment: string

private readonly commentResponseObserver = {
    error: (error: HttpErrorResponse) =&amp;gt; {
        this.alert.handleHttpError(error)
    },
    complete: () =&amp;gt; {
        delete this.newComment
        this.update.emit()
        this.alert.showSuccess('Comment submitted successfully')
    }
}

constructor(
    private commentsService: CommentsService,
    private alert: AlertService,
    private route: ActivatedRoute
) {
}

ngOnInit(): void {
    if (this.comment) {
        this.textArea.nativeElement.focus()
    }
}

submit(): void {
    if (this.requestId) {
        this.addComment()
    } else if (this.comment) {
        this.addReply()
    }
}

addComment(): void {
    if (this.newComment) {
        this.commentsService.addComment(this.requestId, this.newComment)
            .subscribe(this.commentResponseObserver)
    }
}

addReply(): void {
    if (this.newComment) {
        this.commentsService.addReply(this.route.snapshot.queryParamMap.get('requestId'), this.comment, this.newComment)
            .subscribe(this.commentResponseObserver)
    }
}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Comment component HTML&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div class="comment"&amp;gt;
&amp;lt;app-user-image&amp;gt;&amp;lt;/app-user-image&amp;gt;
&amp;lt;div class="position-relative d-inline-block flex-fill"&amp;gt;
    &amp;lt;div class="d-flex justify-content-between align-items-center"&amp;gt;
        &amp;lt;div&amp;gt;&amp;lt;strong&amp;gt;{{comment.author.name}} / {{comment.author.id}}&amp;lt;/strong&amp;gt;&amp;lt;span
            class="date"&amp;gt;{{comment.created | krakenDateTime}}&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;
        &amp;lt;div class="actions"&amp;gt;
            &amp;lt;button *ngIf="this.hateoas.supports(comment, 'update') &amp;amp;&amp;amp; !edit"
                    type="button" class="bg-transparent border-0" title="Edit"
                    (click)="toggleEdit()"&amp;gt;&amp;lt;i class="icon-kraken icon-kraken-edit"&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/button&amp;gt;
            &amp;lt;button *ngIf="this.hateoas.supports(comment, 'delete')"
                    type="button" class="bg-transparent border-0" title="Delete"
                    (click)="displayDeletionConfirmation()"&amp;gt;&amp;lt;i class="icon-kraken icon-kraken-trash"&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/button&amp;gt;
        &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;textarea *ngIf="edit; else readonlyComment"
              #textarea
              class="d-block w-100"
              style="min-height: 7rem;"
              [rows]="rows()"
              [(ngModel)]="commentContent"&amp;gt;&amp;lt;/textarea&amp;gt;
    &amp;lt;ng-template #readonlyComment&amp;gt;
        &amp;lt;div [innerHTML]="commentContentHtml()"&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;/ng-template&amp;gt;
    &amp;lt;strong *ngIf="showReplyButton"
            class="reply-button"
            (click)="toggleReplyComponent()"&amp;gt;&amp;lt;a href="#temporaryLastRow"&amp;gt;Reply&amp;lt;/a&amp;gt;&amp;lt;/strong&amp;gt;
    &amp;lt;/div&amp;gt;
 &amp;lt;/div&amp;gt;
 &amp;lt;div *ngIf="edit" class="animated fadeIn text-right mt-3"&amp;gt;
    &amp;lt;button class="btn btn-sm discard" (click)="cancelEdit()"&amp;gt;Discard&amp;lt;/button&amp;gt;
    &amp;lt;button class="btn btn-sm ml-2 update" (click)="updateComment()"&amp;gt;Update&amp;lt;/button&amp;gt;
 &amp;lt;/div&amp;gt;
 &amp;lt;div class="replies"&amp;gt;
     &amp;lt;app-new-comment *ngIf="showNewReplyWindow"
                 class="d-block mt-3"
                 [comment]="comment"
                 (update)="this.update.emit()"&amp;gt;&amp;lt;/app-new-comment&amp;gt;
    &amp;lt;app-comment *ngIf="firstReply"
             class="d-block my-3"
             [comment]="firstReply"
             (update)="update.emit()"&amp;gt;&amp;lt;/app-comment&amp;gt;
     &amp;lt;div *ngIf="moreReplies.length" class="replies-toggle" (click)="showMoreReplies = 
 !showMoreReplies"&amp;gt;
    &amp;lt;div class="horizontal-bar"&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;span class="mx-3"&amp;gt;{{showMoreReplies ? 'Hide' : 'See'}} {{moreReplies.length}} more 
 comments&amp;lt;/span&amp;gt;
    &amp;lt;div class="horizontal-bar"&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div *ngIf="showMoreReplies"&amp;gt;
    &amp;lt;app-comment *ngFor="let reply of moreReplies"
                 class="d-block my-3"
                 [comment]="reply"
                 (update)="update.emit()"&amp;gt;&amp;lt;/app-comment&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;span id="temporaryLastRow"&amp;gt;&amp;lt;/span&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Comment TS&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export class CommentComponent implements OnInit {

@ViewChild('textarea', {static: true}) textarea: ElementRef&amp;lt;HTMLTextAreaElement&amp;gt;

@Input() comment: CommentDetailsDto
@Output() update = new EventEmitter()

edit = false
showReplyButton = false
showNewReplyWindow = false
showMoreReplies = false
commentContent: string
firstReply: CommentDetailsDto
moreReplies: CommentDetailsDto[]

constructor(
    private commentsService: CommentsService,
    private modalFactoryService: ModalFactoryService,
    public hateoas: HateoasService,
    private alert: AlertService
) {
}

ngOnInit(): void {
    this.commentContent = this.comment.content
    this.showReplyButton = this.hateoas.supports(this.comment, 'reply')
    this.moreReplies = this.comment.replies.reverse().slice(1)
    this.firstReply = this.comment.replies[0]
}

toggleEdit(): void {
    this.edit = !this.edit
}

updateComment(): void {
    this.commentsService.updateComment(this.comment, this.commentContent)
        .subscribe({
            error: (error: HttpErrorResponse) =&amp;gt; {
                this.alert.handleHttpError(error)
            },
            complete: () =&amp;gt; {
                this.alert.showSuccess('Comment updated successfully')
                this.update.emit()
            }
        })
}

cancelEdit(): void {
    this.edit = false
    this.commentContent = this.comment.content
}

displayDeletionConfirmation(): void {
    this.modalFactoryService.openConfirmationModal(
        'Delete Comment',
        {
            message: 'Are you sure you want to delete this comment?',
            yesOptionButton: 'Yes',
            noOptionButton: 'No'
        },
        () =&amp;gt; {
            this.hateoas.execute(this.comment, 'delete')
                .subscribe({
                    error: (error: HttpErrorResponse) =&amp;gt; {
                        this.alert.handleHttpError(error)
                    },
                    complete: () =&amp;gt; {
                        this.alert.showSuccess('Comment deleted successfully')
                        this.update.emit()
                    }
                })
        }
    )
}

toggleReplyComponent(): void {
    this.showNewReplyWindow = !this.showNewReplyWindow
}

commentContentHtml(): string {
    return this.commentContent.replace(/\n/g, '&amp;lt;br&amp;gt;')
}

rows(): number {
    const newLines = this.commentContent.match(/\n/g) || []
    return newLines.length + 1
}
}

 export interface Author {
id: string
name: string
}

 export interface CommentDetailsDto extends Resource {
content: string
author: Author
replies: CommentDetailsDto[]
created: string
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>angular</category>
      <category>typescript</category>
      <category>css</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
