Search code examples
angulartypescriptrxjsobservablengrx

How to Get the last element in Array list of Observable?


This function is to filter an observable off all message from my friend list (onlineUserModel) and to get an observable of type string; lastMessage of each friend

getLastMessage(onlineUserModel : OnlineUserModel): Observable<string>{
    var messagesFriend= this.allDirectMessages$.pipe(map(x => x.filter(f=>f.fromOnlineUser.userName==onlineUserModel.userName)));
    this.lastMessage$ = czt.pipe(map(last()))
    return ...;
  }

lastMessage is Obserbable of string from DirectMessage.messageModel.content; it is a string because if the message is a picture or voice i create a standard message; you have recieved a picture or ...

lastMessage$ : Observable<string>
allDirectMessages$ : Observable<DirectMessage[]> 
 <ul
              class="user-list mt-2"
              *ngFor="let onlineusermodel of onlineUsersModel$ | async"
              (click)="
                selectChat(onlineusermodel);
                removeNotificationForUser(onlineusermodel)
              "
            >
              <li class="user-list-item">
                <div class="avatar avatar-online">
                  <img
                    [src]="onlineusermodel.profilePic"
                    class="rounded-circle"
                    alt="image"
                  />
                </div>

                <div class="users-list-body">
                  <div>
                    <h5>
                      {{ onlineusermodel.userName }}
                    </h5>
                    <p>getLastMessage(onlineUserModel)</p>
                  </div>
                  <div class="last-chat-time">
                    <small class="text-muted">05 min</small>
                    <div
                      *ngIf="{
                        count: getUserNotification(onlineusermodel) | async
                      } as data"
                    >
                      <div class="new-message-count" *ngIf="data.count > 0">
                        {{ data.count }}
                        <!-- {{ getUserNotification(onlineusermodel) | async }} -->
                      </div>
                    </div>
                  </div>
                </div>
              </li>
            </ul>

this is DirectMessage which contain fromOnlineUser


import { MessageViewModel } from "./messageViewModel";
import { OnlineUserModel } from "./onlineUserModel";
export class DirectMessage {
  public fromOnlineUser: OnlineUserModel | null = {
    userName: "",
    email: "",
    firstname: "",
    profilePic: "",
    isProfileComplete: "",
    isActive: "",
  };
  public messages = "";

  public messageModel: MessageViewModel = {
    content: "",
    timestamp: "",
    from: null,
    to: null,
    avatar: "",
    attachement: "",
    fileSize: "",
    fileNameSaved: "",
  };


Solution

  • Assuming they this.allDirectMessages$ emits an array of all dms in chronological order, I would think all you would need would be:

    getLastMessage$({ userName }: OnlineUserModel) {
      return this.allDirectMessages$.pipe(
        map<DirectMessage[], DirectMessage>((dms: DirectMessage[]) => {
          const index: number = dms.lastIndexOf(
            ({fromOnlineUser}: DirectMessage) => fromOnlineUser.userName === userName
          );
          if (index === -1) {
            return null;
          } else {
            return dms[index];
          }
        }),
        map<DirectMessage, string>(this. getMsgFromDirectMsg)
      );
    }
    

    ... assuming this.allDirectMessages$ always completes. If it doesn't complete then the returned observable should also pipe takeUntil(this.destroy$) where destroy$ is a private Subject<void> and there's an ngOnDestroy of

    ngOnDestroy(): void {
      const d$ = this.destroy$;
      if (d$) {
        d$.next();
        d$.complete();
      }
    }
    

    Also, I couldn't tell how to get an actual string from a Directmessage, so I don't know what this.getMsgFromDirectMsg should look like.