Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular6 Div around Arrays from same user

I have some Data for a Messenger:

public messages = [
    {
        direction: 'me', // Required
        user_id: 554, // Required
        user: 'Sven', // Optional
        avatar: 'urltoavatar', // Optional
        message: 'Hi du alter babbsack!' // Optional
    },
    {
        direction: 'others', // Required
        user_id: 8774, // Required
        user: 'Hannes', // Optional
        avatar: 'urltoavatar', // Optional
        message: 'Hey whats going on?' // Optional
    },
    {
        direction: 'others', // Required
        user_id: 8774, // Required
        user: 'Hannes', // Optional
        avatar: 'urltoavatar', // Optional
        message: 'No Idea bro! This ' // Optional
    }
];

I insert this inside the Messenger Message Area: <mark6-messenger-message [messages]="messages" [avatarMe]="false" [avatarOthers]="true"></mark6-messenger-message>

The View of the <mark6-messenger-message> :

<ng-container *ngFor="let message of messages">
    <div class="msg" [ngClass]="message.direction">
        <div class="msg-avatar" *ngIf="(avatarMe && message.direction === 'me') || (avatarOthers && message.direction === 'others')">
            <img [src]="message.avatar" [alt]="message.user">
        </div>
        <div class="msg-content">
            <div class="msg-message">{{message.message}}</div>
        </div>
    </div>
</ng-container>

The Result is this in Browser: (I change the messages in Code, dont worry about this)

enter image description here

The problem is now that when 1 Person Spam some messages, i want to remove the avatars up from the latest message. and i want remove the space between the 2 messages from same person. Like this:

enter image description here

but of 2 different people write it must look like this:

enter image description here

its verry hard for me to figure out how to solve this. and all i ask tell me that there is no way without lost alot of performance. I need to do this in a way, that handle all this stuff automaticly only with the data direction and user (Which means username) or maybe i add a field for user_id then i have 2 required fields ( direction and user_id ) The goal is to make this so easy and automaticly as possible, because this is for the open source lib that i hope in future alot people will use. i dont want to force them to do to much logic stuff. :)

Here is the repository if you need to check other files or more informations: https://github.com/DevMonkeysDE/ngx-mark6/tree/master/projects/mark6-lib/src/lib/messenger

The best thing would be when every pack of messages each person get a div container, then i can work simply with css:first-child and css:last-child. but then it must transform on the fly every message the whole HTML DOM, this is maybe really very very Performance breaking.

like image 797
Budi Avatar asked May 22 '26 02:05

Budi


2 Answers

One possible solution would be to make the *ngIf condition a little more complicated.

Modify the *ngFor directive to keep track of the index of messages like so: *ngFor="let message of messages; let i=index"

Then you could try something like *ngIf="(avatarMe && message.direction === 'me' && (messages[i+1].direction !== 'me') || (avatarOthers && message.direction === 'others' && (messages[i+1].user_id !== message.user_id))", to show the avatar only if the next message is not from the same user.

However, it might not work for the last message as it won't find messages[i+1].

Another solution would be to modify, if possible, the messages array's data structure to include the timestamp (since its a messaging app, it makes more sense to keep track of time). Then we could order by timestamp and show the avatar with the message with greatest timestamp.

like image 62
Sourangshu Sengupta Avatar answered May 24 '26 16:05

Sourangshu Sengupta


What you are after can be accomplished by simply comparing current + next message direction in the ngFor loop and see if they are different then add a "last" or whatever you want to name it class. Because you essentially want the "last of this direction" message.

<div [class]="message.direction" [ngClass]="{last: messages[i+1] && messages[i+1].direction !== message.direction || isLast, message:true}"
 *ngFor="let message of messages; let isLast = last; let i = index;">
    {{message.message}}
</div>
  1. [class]="message.direction"

This will give us the direction of the message as a class me or others in your case, pretty straight forward.

Now let me explain the "last" class part:

  1. *ngFor="let message of messages; let isLast = last; let i = index;"

The ngFor directive exposes some local variables like last, first,, index, so we can take advantage of that and assign our isLast variable to last local variable from ngFor loop, at same time our i variable will hold the current index ngFoor loop. Docs for ngFor

  1. [ngClass]="{last: messages[i+1] && messages[i+1].direction !== message.direction || isLast, message:true}

We use the ngClass directive to apply last class if our condition is true, in this case condition is just comparing if the next message in the loop (messages[i+1].direction) is not the same as current message in the loop message.direction. The only problem with this is the very last message in the loop messages[i+1] will be undefined, and that's where the or || isLast check comes thru, as this will always be true for last message in the loop. Docs for ngClass

As an aside, messages[i+1] && messages[i+1].direction you need to do it this way so you short circuit your condition check direction only if messages[i+1] is defined, otherwise your code will crash on the last item. You can read more about that in the Javascript docs

For showing/hiding avatars, that's just simple css once you have the last class in there.

Here's a working example: https://stackblitz.com/edit/angular-gwqqee

Hope that helps.

EDIT: I forgot you have more than two users, but same concept applies, just check user_id instead of direction, see updated example.

[ngClass]="{
  'message': true,
  'last-from-direction': messages[i+1] && messages[i+1].direction !== message.direction || isLast,
  'last-from-user': messages[i+1] && messages[i+1].user_id !== message.user_id || isLast
  }"
like image 25
eblin Avatar answered May 24 '26 16:05

eblin



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!