Model
Create a new interface _models/Message.ts
export interface Message {
id: number;
senderId: number;
senderKnownAs: string;
senderPhotoUrl: string;
recipientId: number;
recipientKnownAs: string;
recipientPhotoUrl: string;
content: string;
sentDate: Date;
isRead: boolean;
readDate: Date;
}
Service
We will use the UserService, it can be argued that a new service for the messages is a better choice.
Add new method getMessages
getMessages(
userId: number, pageNumber?: number, itemsPerPage?: number, messageContainer?: string
): Observable<PaginatedResult<Message[]>> {
let params = new HttpParams();
if (pageNumber !== null && itemsPerPage !== null) {
params = params.set('pageNumber', pageNumber.toString()).set('pageSize', itemsPerPage.toString());
}
if (messageContainer !== null) {
params = params.set('messageContainer', messageContainer);
}
return this.http
.get<Message[]>(this.baseUrl + userId + '/messages', {
params: params,
observe: 'response'
})
.pipe(
map(response => {
const paginatedResults = new PaginatedResult<Message[]>();
paginatedResults.result = response.body;
if (response.headers.get('Pagination') !== null) {
paginatedResults.pagination = JSON.parse(response.headers.get('Pagination'));
}
return paginatedResults;
})
);
}
Resolver
Create a new resolver messages.resolver.ts
@Injectable()
export class MessagesResolver implements Resolve<PaginatedResult<Message[]>> {
pageNumber = 1;
pageSize = 5;
messageContainer = 'Unread';
constructor(
private userService: UserService,
private authService: AuthService,
private router: Router,
private alertify: AlertifyService
) {}
resolve(route: ActivatedRouteSnapshot): Observable<PaginatedResult<Message[]>> {
return this.userService.getMessages(this.authService.getUserId(), this.pageNumber, this.pageSize, this.messageContainer).pipe(
catchError(error => {
this.alertify.error('Problem retrieving messages');
this.router.navigate(['/home']);
return empty();
})
);
}
}
Register the resolver in app.module.ts in the providers.
Add the resolver in routes.ts
{
path: 'messages',
component: MessagesComponent,
resolve: { messages: MessagesResolver }
}
Component
Open messages.component.ts
@Component({
selector: 'app-messages',
templateUrl: './messages.component.html',
styleUrls: ['./messages.component.css']
})
export class MessagesComponent implements OnInit {
messages: Message[];
pagination: Pagination;
messageContainer: 'Unread';
constructor(
private userService: UserService,
private authService: AuthService,
private route: ActivatedRoute,
private alertify: AlertifyService
) {}
ngOnInit() {
this.route.data.subscribe(data => {
const paginatedResult = <PaginatedResult<Message[]>>data['messages'];
this.messages = paginatedResult.result;
this.pagination = paginatedResult.pagination;
});
}
loadMessages() {
this.userService
.getMessages(
this.authService.getUserId(),
this.pagination.currentPage,
this.pagination.itemsPerPage,
this.messageContainer
)
.subscribe(
paginatedResult => {
this.messages = paginatedResult.result;
this.pagination = paginatedResult.pagination;
},
error => this.alertify.error(error)
);
}
pageChanged(event: any): void {
this.pagination.currentPage = event.page;
this.loadMessages();
}
}
Template
Open message.component.html
<div class="container mt-5">
<div class="row">
<div class="btn-group" btnRadioGroup [(ngModel)]="this.messageContainer">
<label class="btn btn-primary" btnRadio="Unread" (click)="loadMessages()">
<i class="fa fa-envelope"></i> Unread
</label>
<label class="btn btn-primary" btnRadio="Inbox" (click)="loadMessages()">
<i class="fa fa-envelope-open"></i> Inbox
</label>
<label class="btn btn-primary" btnRadio="Outbox" (click)="loadMessages()">
<i class="fa fa-paper-plane"></i> Outbox
</label>
</div>
</div>
<div class="row" *ngIf="messages.length == 0">
<h3>No messages</h3>
</div>
<div class="row" *ngIf="messages.length > 0">
<table class="table table-hover" style="cursor: pointer">
<tr>
<th style="width: 40%">Message</th>
<th style="width: 20%">From / To</th>
<th style="width: 20%">Sent / Received</th>
<th style="width: 20%"></th>
</tr>
<tr *ngFor="let message of messages" [routerLink]="['/members',
messageContainer == 'Outbox' ? message.recipientId : message.senderId]">
<td>{{message.content}}</td>
<td>
<div *ngIf="messageContainer != 'Outbox'">
<img src={{message?.senderPhotoUrl}} class="img-circle rounded-circle mr-1">
<strong>{{message.senderKnownAs}}</strong>
</div>
<div *ngIf="messageContainer == 'Outbox'">
<img src={{message?.recipientPhotoUrl}} class="img-circle rounded-circle mr-1">
<strong>{{message.recipientKnownAs}}</strong>
</div>
</td>
<td>{{message.sentDate | timeAgo}}</td>
<td>
<button class="btn btn-danger">Delete</button>
</td>
</tr>
</table>
</div>
</div>
<div class="d-flex justify-content-center" *ngIf="messages.length > 0">
<pagination [boundaryLinks]="true" [totalItems]="pagination.totalItems" [itemsPerPage]="pagination.itemsPerPage" [(ngModel)]="pagination.currentPage"
(pageChanged)="pageChanged($event)" previousText="‹" nextText="›" firstText="«" lastText="»">
</pagination>
</div>
Add some style in message.component.css
table {
margin-top: 15px;
}
.img-circle {
max-height: 50px;
}
td {
vertical-align: middle;
}