We are currently developing a chat component where users can click on the left side chat item to open messages with the selected user. We have implemented an active class that changes the color of the selected chat list item. Our goal is to apply the active class when any chat list item is selected. Here is the code snippet:
Messages service
import { Observable } from 'rxjs';
import { HttpClient } from '@angular/common/http';
import { Injectable,EventEmitter } from '@angular/core';
import { Message } from '@angular/compiler/src/i18n/i18n_ast';
const BASEURL = 'http://localhost:3000/api/chatapp';
@Injectable({
providedIn: 'root'
})
export class MessageService {
constructor(private http: HttpClient) {}
SendMessage(senderId, receiverId, receiverName, message): Observable<any> {
return this.http.post(`${BASEURL}/chat-messages/${senderId}/${receiverId}`, {
receiverId,
receiverName,
message
});
}
GetAllMessages(senderId, receiverId): Observable<any> {
return this.http.get(`${BASEURL}/chat-messages/${senderId}/${receiverId}`);
}
MarkMessages(sender, receiver): Observable<any> {
return this.http.get(`${BASEURL}/receiver-messages/${sender}/${receiver}`);
}
MarkAllMessages(): Observable<any> {
return this.http.get(`${BASEURL}/mark-all-messages`);
}
chatSelected = new EventEmitter<Message>();
}
Route
path: 'chat/:name',
component: MessageComponent,
canActivate: [AuthGuard]
HTML
<div id="frame">
<div id="sidepanel">
<div id="contacts" >
<ul *ngFor="let chat of chatList">
<li class="contact"
[ngClass]="{'active': chat.receiverId.username === this.selectedChat.receiverId.username}">
<div class="wrap" (click)="GoToChatPage(chat.receiverId.username)">
<span class="contact-status online"></span>
<img src="http://res.cloudinary.com/ratingapp/image/upload/v{{chat.receiverId.picVersion}}/{{chat.receiverId.picId}}" alt="" />
<div class="meta">
<p class="name">{{chat.receiverId.username}}</p>
<p class="preview">
{{chat.msgId.message[chat.msgId.message.length - 1].body.substr(0, 10)}}...</p>
</div>
</div>
</li>
</ul>
</div>
</div>
<div class="content">
<div class="contact-profile">
<img src="http://emilcarlsson.se/assets/harveyspecter.png" alt="" />
<p>Harvey Specter</p>
<div class="social-media">
<i class="material-icons">cancel</i>
</div>
</div>
<div class="messages">
<ul *ngFor="let message of messagesArray">
<li class="sent" *ngIf="user.username !== receiver && user.username !== message.sendername">
<img src="http://res.cloudinary.com/ratingapp/image/upload/v{{chat.receiverId.picVersion}}/{{chat.receiverId.picId}}" alt="" />
<p>{{message.body}}</p>
</li>
<li class="replies" *ngIf="user.username === message.sendername">
<img src="http://res.cloudinary.com/ratingapp/image/upload/v{{chat.receiverId.picVersion}}/{{chat.senderId.picId}}" alt="" />
<p>{{message.body}}</p>
</li>
</ul>
</div>
<form (ngSubmit)="SendMessage()">
<div class="message-input">
<div class="wrap">
<input [(ngModel)]="message" (keypress)="IsTyping()" type="text" placeholder="Write your message..." />
<button class="emojiBtn" (click)="Toggled()">😄</button>
<div class="emoji-content-editable" (emojiPickerCaretEmitter)="HandleCurrentCaret($event)" (input)="content = $event.target.textContent"
[textContent]="content" contenteditable="true"></div>
<i class="emoji-toggle-button imgBtn" [(emojiPickerIf)]="toggled" [emojiPickerPreserveSelection]="false" [emojiPickerDirection]="direction"
[emojiPickerAutofocus]="true" (emojiPickerSelect)="HandleSelection($event)"></i>
<button class="submit"><i class="fa fa-paper-plane" aria-hidden="true"></i></button>
</div>
</div>
</form>
</div>
</div>
TypeScript
export class MessageComponent implements OnInit {
@Input() users;
receiver: string;
user: any;
message: string;
receiverData: any;
messagesArray = [];
socket: any;
typingMessage;
typing = false;
isOnline = false;
chatList = [];
public eventMock;
public eventPosMock;
public direction =
Math.random() > 0.5 ? (Math.random() > 0.5 ? 'top' : 'bottom') : Math.random() > 0.5 ? 'right' : 'left';
public toggled = false;
public content = ' ';
private _lastCaretEvent: CaretEvent;
constructor(
private tokenService: TokenService,
private msgService: MessageService,
private route: ActivatedRoute,
private usersService: UsersService
) {
this.socket = io('http://localhost:3000');
}
ngOnInit() {
this.user = this.tokenService.GetPayload();
this.route.params.subscribe(params => {
this.receiver = params.name;
this.GetUserByUsername(this.receiver);
this.socket.on('refreshPage', () => {
this.GetUserByUsername(this.receiver);
});
});
this.socket.on('is_typing', data => {
if (data.sender === this.receiver) {
this.typing = true;
}
});
this.socket.on('has_stopped_typing', data => {
if (data.sender === this.receiver) {
this.typing = false;
}
});
}
ngOnChanges(changes: SimpleChanges) {
const title = document.querySelector('.nameCol');
if (changes.users.currentValue.length > 0) {
const result = _.indexOf(changes.users.currentValue, this.receiver);
if (result > -1) {
this.isOnline = true;
(title as HTMLElement).style.marginTop = '10px';
} else {
this.isOnline = false;
(title as HTMLElement).style.marginTop = '20px';
}
}
}
ngAfterViewInit() {
const params = {
room1: this.user.username,
room2: this.receiver
};
this.socket.emit('join chat', params);
}
GetUser(id) {
this.usersService.GetUserById(id).subscribe(data => {
this.chatList = data.result.chatList;
});
}
GetUserByUsername(name) {
this.usersService.GetUserByName(name).subscribe(data => {
this.receiverData = data.result;
this.GetMessages(this.user._id, data.result._id);
});
}
GoToChatPage(chat, name) {
this.selectedChat = chat;
this.router.navigate(['chat', name]);
this.msgService.MarkMessages(this.user.username, name).subscribe(data => {
this.socket.emit('refresh', {});
});
}
GetMessages(senderId, receiverId) {
this.msgService.GetAllMessages(senderId, receiverId).subscribe(data => {
this.messagesArray = data.messages.message;
});
}
SendMessage() {
if (this.message) {
this.msgService
.SendMessage(this.user._id, this.receiverData._id, this.receiverData.username, this.message)
.subscribe(data => {
this.socket.emit('refresh', {});
this.message = '';
});
}
}
HandleSelection(event: EmojiEvent) {
this.content =
this.content.slice(0, this._lastCaretEvent.caretOffset) +
event.char +
this.content.slice(this._lastCaretEvent.caretOffset);
this.eventMock = JSON.stringify(event);
this.message = this.content;
this.toggled = !this.toggled;
this.content = '';
}
HandleCurrentCaret(event: CaretEvent) {
this._lastCaretEvent = event;
this.eventPosMock = `{ caretOffset : ${event.caretOffset}, caretRange: Range{...}, textContent: ${
event.textContent
} }`;
}
Toggled() {
this.toggled = !this.toggled;
}
IsTyping() {
this.socket.emit('start_typing', {
sender: this.user.username,
receiver: this.receiver
});
if (this.typingMessage) {
clearTimeout(this.typingMessage);
}
this.typingMessage = setTimeout(() => {
this.socket.emit('stop_typing', {
sender: this.user.username,
receiver: this.receiver
});
}, 500);
}
}
If you have any ideas on how to add an event emitter for the active class functionality in this case, please share your thoughts!