File
Implements
Index
Properties
|
|
Methods
|
|
Inputs
|
|
Outputs
|
|
isTyping
|
Type : boolean
|
Default value : false
|
|
Methods
ngAfterViewChecked
|
ngAfterViewChecked()
|
|
|
onNewMessageFocus
|
onNewMessageFocus(event: boolean)
|
|
Parameters :
Name |
Type |
Optional |
event |
boolean
|
No
|
|
scrollToBottom
|
scrollToBottom()
|
|
|
sendNewMessage
|
sendNewMessage()
|
|
|
_isAgentTyping
|
Default value : false
|
|
agentColor
|
Type : string
|
Default value : '#29b6f6'
|
|
colors
|
Type : []
|
Default value : [
'#81c784',
'#ffab91',
'#f48fb1',
'#29b6f6',
'#e1bee7',
'#9ccc65',
'#ffc107',
'#26c6da',
'#cddc39',
]
|
|
colorsIndex
|
Type : number
|
Default value : 0
|
|
Private
lastCount
|
Default value : -1
|
|
messagesContainer
|
Type : ElementRef
|
Decorators :
@ViewChild('MessagesContainer', {static: true})
|
|
newMessageText
|
Type : string
|
Default value : ''
|
|
usernameToColor
|
Type : literal type
|
Default value : {}
|
|
import { Component, Input, Output, EventEmitter, ViewChild, ElementRef, AfterViewChecked } from '@angular/core';
import { IChatMessage, IChatMessageType } from '../../models/chat.message';
import { IChatSettings } from '../../models/chat.settings';
@Component({
selector: 'app-chat-box',
templateUrl: './chat-box.component.html',
styleUrls: ['./chat-box.component.scss'],
})
export class ChatBoxComponent implements AfterViewChecked {
@Input() settings: IChatSettings;
@Input() isTyping = false;
@Input() messages: IChatMessage[];
private lastCount = -1;
_isAgentTyping = false;
@Output() isAgentTyping = new EventEmitter<boolean>();
@Output() newMessage = new EventEmitter<string>();
newMessageText = '';
@ViewChild('MessagesContainer', { static: true }) messagesContainer: ElementRef;
usernameToColor: { [username: string]: string } = {};
colors = [
'#81c784',
'#ffab91',
'#f48fb1',
'#29b6f6',
'#e1bee7',
'#9ccc65',
'#ffc107',
'#26c6da',
'#cddc39',
];
colorsIndex = 0;
agentColor = '#29b6f6';
constructor() { }
ngAfterViewChecked() {
if (this.lastCount !== this.messages.length) {
this.lastCount = this.messages.length;
this.scrollToBottom();
}
}
getColor(message: IChatMessage) {
if (message.type && message.type === IChatMessageType.AGENT) {
return this.agentColor;
} else if (message.username) {
if (!this.usernameToColor[message.username]) {
this.usernameToColor[message.username] = this.colors[this.colorsIndex];
this.colorsIndex = (this.colorsIndex + 1) % this.colors.length;
}
return this.usernameToColor[message.username];
} else {
return this.colors[0];
}
}
shouldAlignRight(message: IChatMessage) {
return message.type && message.type === IChatMessageType.AGENT;
}
sendNewMessage() {
if (this.newMessageText) {
this.newMessage.emit(this.newMessageText);
this.newMessageText = '';
}
}
onNewMessageFocus(event: boolean) {
const isTyping = event && this.newMessageText.length > 0;
if (isTyping !== this._isAgentTyping) {
this._isAgentTyping = isTyping;
this.isAgentTyping.emit(isTyping);
}
}
onKeyup() {
const isTyping = this.newMessageText.length > 0;
if (isTyping !== this._isAgentTyping) {
this._isAgentTyping = isTyping;
this.isAgentTyping.emit(isTyping);
}
}
scrollToBottom() {
try {
this.messagesContainer.nativeElement.scrollTop = this.messagesContainer.nativeElement.scrollHeight;
}
catch (e) { }
}
}
<div class="chat-box">
<div #MessagesContainer class="messages" [style.max-height]='settings.maxHeight'>
<ng-container *ngFor="let message of messages">
<app-chat-message [alignRight]="shouldAlignRight(message)" [message]="message.text" [username]="message.username"
[timestamp]="message.timestamp" [image]="message.userIcon" [fallbackImage]="settings.fallbackUserIcon" [color]="getColor(message)">
</app-chat-message>
</ng-container>
<div *ngIf="isTyping" class="typing-indicator">
Someone is typing
<span></span>
<span></span>
<span></span>
</div>
</div>
<div class="new-message">
<input #NewMessageText [(ngModel)]="newMessageText" type="text" placeholder="Type a message" (focus)="onNewMessageFocus(true)"
(blur)="onNewMessageFocus(false)" (keydown.enter)="sendNewMessage()" (keyup)='onKeyup()' [disabled]="settings.disableSendMessage">
<input type="image" [src]="settings.sendImage" (click)="sendNewMessage()" [disabled]="settings.disableSendMessage">
</div>
</div>
$background-color: #eceff1;
.chat-box{
background-color: $background-color;
}
.messages {
padding: 5px;
overflow: auto;
min-height: 50px;
}
.new-message{
border-top: solid black 1px;
display: flex;
align-content: center;
height: 25px;
input[type=text]{
flex: 1 1 0;
background-color: $background-color;
border: none;
min-width: 0;
}
input[type=image]{
position: relative;
top: 50%;
transform: translateY(-50%);
height: 20px;
cursor: pointer;
}
input[type=image]:disabled
{
opacity:0.5;
cursor:auto;
}
input:focus{
outline: none;
}
}
.typing-indicator{
font-size: 1em;
font-style: italic;
$size: 10px;
span {
display: inline-block;
height: $size;
width: $size;
border-radius: 50%;
background-color: #9e9e9e;
margin: 0 1px;
opacity: .2;
@for $i from 1 through 3 {
&:nth-of-type(#{$i}) {
animation: 1.5s blink infinite ($i * .33333s);
}
}
}
@keyframes blink {
50% {
opacity: 1;
}
}
}
Legend
Html element with directive