在Conduit应用中,我们能够对文章留下评论。要建立这个功能,我们首先需要创建一个评论模型。
创建评论模型
src/app/shared/models/comment.model.ts
import { Profile } from './profile.model';export class Comment {id: number;body: string;createdAt: string;author: Profile;}
src/app/shared/models/index.ts
export * from './article.model';+export * from './comment.model';export * from './errors.model';export * from './profile.model';export * from './user.model';
我们需要一种创建、获取和删除评论的方法,所以让我们创建一个服务来处理这个问题。
创建评论服务
src/app/shared/services/comments.service.ts
import { Injectable } from '@angular/core';import { Observable } from 'rxjs/Rx';import 'rxjs/add/operator/map';import 'rxjs/add/operator/catch';import { ApiService } from './api.service';import { Comment } from '../models';@Injectable()export class CommentsService {constructor (private apiService: ApiService) {}add(slug, payload): Observable<Comment> {return this.apiService.post(`/articles/${slug}/comments`, { comment: { body: payload } }).map(data => data.comment);}getAll(slug): Observable<Comment[]> {return this.apiService.get(`/articles/${slug}/comments`).map(data => data.comments);}destroy(commentId, articleSlug) {return this.apiService.delete(`/articles/${articleSlug}/comments/${commentId}`);}}
将我们的评论服务导出到我们的应用程序
src/app/shared/services/index.ts
export * from './api.service';export * from './articles.service';export * from './auth-guard.service';+export * from './comments.service';export * from './jwt.service';export * from './profiles.service';export * from './user.service';
而我们需要将其包含在app模块中。
src/app/app.module.ts
[...]import { RouterModule } from '@angular/router';import { AppComponent } from './app.component';import { ArticleModule } from './article/article.module';import { AuthModule } from './auth/auth.module';import { EditorModule } from './editor/editor.module';import { HomeModule } from './home/home.module';[...]ApiService,ArticlesService,AuthGuard,+ CommentsService,FooterComponent,HeaderComponent,JwtService,[...]ApiService,ArticlesService,AuthGuard,+ CommentsService,JwtService,ProfilesService,UserService[...]
让我们来创建一个用于显示单个评论的组件
创建ArticleComment组件
src/app/article/article-comment.component.html
<div class="card"><div class="card-block"><p class="card-text">{{ comment.body }}</p></div><div class="card-footer"><a class="comment-author" [routerLink]="['/profile', comment.author.username]"><img [src]="comment.author.image" class="comment-author-img" /></a> <a class="comment-author" [routerLink]="['/profile', comment.author.username]">{{ comment.author.username }}</a><span class="date-posted">{{ comment.createdAt | date: 'longDate' }}</span><span class="mod-options" [hidden]="!canModify"><i class="ion-trash-a" (click)="deleteClicked()"></i></span></div></div>
src/app/article/article-comment.component.ts
import { Component, EventEmitter, Input, Output, OnInit } from '@angular/core';import { Comment, User, UserService } from '../shared';@Component({selector: 'article-comment',templateUrl: './article-comment.component.html'})export class ArticleCommentComponent implements OnInit {constructor(private userService: UserService) {}@Input() comment: Comment;@Output() deleteComment = new EventEmitter<boolean>();canModify: boolean;ngOnInit() {// Load the current user's datathis.userService.currentUser.subscribe((userData: User) => {this.canModify = (userData.username === this.comment.author.username);});}deleteClicked() {this.deleteComment.emit(true);}}
我们需要在ArticleModule中声明这个组件才能使用它。
src/app/article/article.module.ts
import { ModuleWithProviders, NgModule } from '@angular/core';import { RouterModule } from '@angular/router';import { ArticleComponent } from './article.component';+import { ArticleCommentComponent } from './article-comment.component';import { ArticleResolver } from './article-resolver.service';import { MarkdownPipe } from './markdown.pipe';import { SharedModule } from '../shared';const articleRouting: ModuleWithProviders = RouterModule.forChild([{path: 'article/:slug',component: ArticleComponent,resolve: {article: ArticleResolver}}]);@NgModule({imports: [articleRouting,SharedModule],declarations: [ArticleComponent,+ ArticleCommentComponent,MarkdownPipe],providers: [ArticleResolver]})export class ArticleModule {}
接下来,我们需要更新文章组件,使用我们新创建的ArticleComment服务来处理检索、创建和删除评论。
用检索、创建和删除注释来更新ArticleComponent
src/app/article/article.component.ts
import { Component, OnInit } from '@angular/core';import { FormControl } from '@angular/forms';import { ActivatedRoute, Router } from '@angular/router';import {Article,ArticlesService,+ Comment,+ CommentsService,User,UserService} from '../shared';@Component({selector: 'article-page',templateUrl: './article.component.html'})export class ArticleComponent implements OnInit {article: Article;currentUser: User;canModify: boolean;+ comments: Comment[];+ commentControl = new FormControl();+ commentFormErrors = {};isSubmitting = false;isDeleting = false;constructor(private route: ActivatedRoute,private articlesService: ArticlesService,+ private commentsService: CommentsService,private router: Router,private userService: UserService,) { }ngOnInit() {// Retreive the prefetched articlethis.route.data.subscribe((data: { article: Article }) => {this.article = data.article;++ // Load the comments on this article+ this.populateComments();});// Load the current user's datathis.userService.currentUser.subscribe((userData: User) => {this.currentUser = userData;this.canModify = (this.currentUser.username === this.article.author.username);});}onToggleFavorite(favorited: boolean) {this.article.favorited = favorited;if (favorited) {this.article.favoritesCount++;} else {this.article.favoritesCount--;}}onToggleFollowing(following: boolean) {this.article.author.following = following;}deleteArticle() {this.isDeleting = true;this.articlesService.destroy(this.article.slug).subscribe(success => {this.router.navigateByUrl('/');});}+ populateComments() {+ this.commentsService.getAll(this.article.slug)+ .subscribe(comments => this.comments = comments);+ }++ addComment() {+ this.isSubmitting = true;+ this.commentFormErrors = {};++ let commentBody = this.commentControl.value;+ this.commentsService+ .add(this.article.slug, commentBody)+ .subscribe(+ comment => {+ this.comments.unshift(comment);+ this.commentControl.reset('');+ this.isSubmitting = false;+ },+ errors => {+ this.isSubmitting = false;+ this.commentFormErrors = errors;+ }+ );+ }+ onDeleteComment(comment) {+ this.commentsService.destroy(comment.id, this.article.slug)+ .subscribe(+ success => {+ this.comments = this.comments.filter((item) => item !== comment);+ }+ );+ }}
然后我们就可以更新文章模板来挂入组件的新方法。
更新ArticleComponent模板
src/app/article/article.component.html
[...]<div class="row"><div class="col-xs-12 col-md-8 offset-md-2">+ <div *showAuthed="true">+ <list-errors [errors]="commentFormErrors"></list-errors>+ <form class="card comment-form" (ngSubmit)="addComment()">+ <fieldset [disabled]="isSubmitting">+ <div class="card-block">+ <textarea class="form-control"+ placeholder="Write a comment..."+ rows="3"+ [formControl]="commentControl"+ ></textarea>+ </div>+ <div class="card-footer">+ <img [src]="currentUser.image" class="comment-author-img" />+ <button class="btn btn-sm btn-primary" type="submit">+ Post Comment+ </button>+ </div>+ </fieldset>+ </form>+ </div><div *showAuthed="false"><a [routerLink]="['/login']">Sign in</a> or <a [routerLink]="['/register']">sign up</a> to add comments on this article.</div>+ <article-comment+ *ngFor="let comment of comments"+ [comment]="comment"+ (deleteComment)="onDeleteComment(comment)">+ </article-comment></div></div>[...]
我们现在有了对文章的评论功能!
你可以将你的代码与Github上的有效代码进行比较,或者在本地检查分支:
git checkout m-1
