I need some help here please...
Im making a chat app with angular and material, and i need to show the user nickname only one time before the next user messages enter in action (like whatsapp or similar), something like this:
user1: message 1 message 2 message 3 user2: message 1 message 2 user1: message 4 etc
This is my component.ts:
messages: any[] = [
{
nickname: 'user1',
msg: 'hola que tal 1',
img: "https://images-na.ssl-images-amazon.com/images/I/81PohdE46lL.jpg"
},
{
nickname: 'user1',
msg: 'hola que tal 2',
img: "https://images-na.ssl-images-amazon.com/images/I/81PohdE46lL.jpg"
},
{
nickname: 'user1',
msg: 'hola que tal 3',
img: "https://images-na.ssl-images-amazon.com/images/I/81PohdE46lL.jpg"
},
{
nickname: 'user2',
msg: 'hola que tal 4',
img: "https://images-na.ssl-images-amazon.com/images/I/81PohdE46lL.jpg"
},
{
nickname: 'user2',
msg: 'hola que tal 4',
img: "https://images-na.ssl-images-amazon.com/images/I/81PohdE46lL.jpg"
},
];
username: string = "test";
temp_user: string = "";
changeTemp(nickname: string): void {
this.temp_user = nickname;
}
And this is my HTML with the (ugly) solution im achieved:
<mat-card-content>
<div class="chat-window" #chat_window>
<mat-list role="list">
<div *ngFor="let msg of messages">
<div *ngIf="temp_user !== msg.nickname" class="avatar"
[ngClass]="{ 'right-avatar': msg.nickname == username}">
<!-- <img class="avatar-img" [src]="msg.img" alt="..."> -->
{{ msg.nickname }}
{{ changeTemp(msg.nickname) }}
</div>
<mat-list-item class="chat-message" role="listitem"
[ngClass]="{ 'right-message': msg.nickname == username}">
{{ msg.msg }}
</mat-list-item>
</div>
</mat-list>
</div>
</mat-card-content>
This is the result: result I called the changeTemp() function with string interpolation to save temp user and check if its repeated before next user msg with an ngIf but this (call a function in this situation) not sounds like a good practice to me...
There is a clean way to solve this? get temp user in some way or an alternative? i have tried with a directive that emits an event, and a trackBy solution, but not worked fine in this situation.
Thanks a lot.
You can group your list in a more convenient order before you throw it to HTML to do its job.
Assume that your array is,
var arr = [
{tag: 'one', content: 'A'},
{tag: 'one', content: 'B'},
{tag: 'two', content: 'C'},
{tag: 'two', content: 'D'},
{tag: 'three', content: 'E'},
{tag: 'three', content: 'F'}
];
Convenient order would like,
{
one: [
{tag: 'one', content: 'A'},
{tag: 'one', content: 'B'}
],
two: [
{tag: 'two', content: 'C'},
{tag: 'two', content: 'D'}
],
three: [
{tag: 'three', content: 'E'},
{tag: 'three', content: 'F'}
]
}
you can group the array by using "group-array" package or manually. If you wish to use "group-array" package, bellow I have mentioned the link and a example copied from original documentation to group the array. Link : https://www.npmjs.com/package/group-array#examples
//npm i group-array
// group by the `tag` property
groupArray(arr, 'tag');
In your HTML
<div *ngFor="let item of yourList | keyvalue">
<div >
Message From - {{item.key}}
</div>
<div>
<p *ngFor="let message of item.value">
{{message.content}}
</p>
</div>
</div>
Output :
Message From - one
A
B
Message From - three
E
F
Message From - two
C
D