ค้นหาเว็บไซต์

json - Angular6 Div รอบ Arrays จากผู้ใช้เดียวกัน


ฉันมีข้อมูลสำหรับ 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
    }
];

ฉันใส่สิ่งนี้ลงในพื้นที่ข้อความของ Messenger: <mark6-messenger-message [messages]="messages" [avatarMe]="false" [avatarOthers]="true"></mark6-messenger-message>

มุมมองของ <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>

ผลลัพธ์ในเบราว์เซอร์เป็นแบบนี้: (ฉันเปลี่ยนข้อความในโค้ด ไม่ต้องกังวลเรื่องนี้)

ปัญหาตอนนี้คือเมื่อมีคนส่งข้อความสแปมหลายข้อความ ผมต้องการลบอวาตาร์จากข้อความล่าสุด และผมต้องการลบช่องว่างระหว่างข้อความสองข้อความจากคนเดียวกัน แบบนี้:

แต่ถ้ามีคนสองคนเขียน มันต้องดูเหมือนแบบนี้:

มันยากมากสำหรับฉันที่จะหาวิธีแก้ปัญหานี้ และทั้งหมดที่ฉันขอคือบอกฉันว่ามันไม่มีทางที่จะทำได้โดยไม่เสียประสิทธิภาพมากนัก ฉันจำเป็นต้องทำสิ่งนี้ในวิธีที่จัดการทุกอย่างโดยอัตโนมัติด้วยเพียงข้อมูล direction และ user (ซึ่งหมายถึงชื่อผู้ใช้) หรือบางทีฉันอาจเพิ่มฟิลด์สำหรับ user_id แล้วฉันจะมีสองฟิลด์ที่จำเป็น ( direction และ user_id ) เป้าหมายคือทำให้สิ่งนี้ง่ายและเป็นอัตโนมัติมากที่สุด เพราะนี่คือสำหรับไลบรารีโอเพ่นซอร์สที่ฉันหวังว่าในอนาคตจะมีคนใช้มากมาย ฉันไม่อยากบังคับให้พวกเขาต้องทำตรรกะมากเกินไป :)

นี่คือที่เก็บข้อมูลถ้าคุณต้องการตรวจสอบไฟล์อื่นหรือข้อมูลเพิ่มเติม: https://github.com/DevMonkeysDE/ngx-mark6/tree/master/projects/mark6-lib/src/lib/messenger

สิ่งที่ดีที่สุดคือเมื่อแต่ละแพ็คของข้อความที่แต่ละคนได้รับมีคอนเทนเนอร์ div ของตัวเอง แล้วฉันจะสามารถทำงานง่ายๆ กับ css:first-child และ css:last-child แต่ต่อมามันจะต้องแปลงทุกข้อความของ DOM HTML ทั้งหมดแบบทันที นี่อาจจะทำให้ประสิทธิภาพแย่ลงจริงๆ

คำตอบ #1

วิธีแก้ปัญหาหนึ่งที่เป็นไปได้คือการทำให้เงื่อนไข *ngIf ซับซ้อนมากขึ้นเล็กน้อย

ปรับแก้ไดเร็กทีฟ *ngFor เพื่อเก็บติดตามดัชนีของข้อความดังนี้: *ngFor="let message of messages; let i=index"

จากนั้นคุณสามารถลองใช้สิ่งที่คล้ายกับ *ngIf="(avatarMe && message.direction === 'me' && (messages[i+1].direction !== 'me') || (avatarOthers && message.direction === 'others' && (messages[i+1].user_id !== message.user_id))" เพื่อแสดงอวาตาร์ ก็ต่อเมื่อข้อความถัดไปไม่ใช่ของผู้ใช้คนเดียวกัน

อย่างไรก็ตาม มันอาจจะใช้ไม่ได้กับข้อความสุดท้ายเพราะจะไม่พบ messages[i+1]

อีกวิธีแก้ปัญหาคือการปรับโครงสร้างข้อมูลของอาเรย์ messages หากเป็นไปได้ เพื่อรวม timestamp (เนื่องจากเป็นแอปส่งข้อความ การติดตามเวลาเป็นเรื่องที่สมเหตุสมผลมากกว่า) จากนั้นเราสามารถจัดลำดับตาม timestamp และแสดงอวาตาร์พร้อมข้อความที่มี timestamp มากที่สุดได้

คำตอบ #2

สิ่งที่คุณต้องการสามารถทำได้โดยการเปรียบเทียบทิศทางของข้อความปัจจุบัน + ถัดไปในลูป ngFor แล้วดูว่าพวกมันต่างกันหรือไม่ จากนั้นเพิ่มคลาสชื่อ "last" หรือชื่ออะไรก็ได้ที่คุณต้องการ เพราะโดยพื้นฐานคุณต้องการข้อความ "ล่าสุดของทิศทางนี้"

<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"

นี่จะแจ้งทิศทางของข้อความให้เราเป็นคลาส me หรือ others ในกรณีของคุณ ค่อนข้างตรงไปตรงมา

ตอนนี้ให้ฉันอธิบายส่วนของชั้นเรียน 'สุดท้าย':

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

คำสั่ง ngFor จะเปิดเผยตัวแปรท้องถิ่นบางตัว เช่น last, first, index ดังนั้นเราสามารถใช้ประโยชน์จากสิ่งนั้นและกำหนดตัวแปร isLast ของเราให้กับตัวแปรท้องถิ่น last จากลูป ngFor พร้อมกัน ตัวแปร i ของเราจะเก็บค่า index ปัจจุบันของลูป ngFor เอกสารสำหรับ ngFor

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

เราใช้ directive ngClass เพื่อใช้คลาส last หากเงื่อนไขของเราถูกต้อง ในกรณีนี้เงื่อนไขคือการเปรียบเทียบว่าข้อความถัดไปในลูป (messages[i+1].direction) ไม่เหมือนกับข้อความปัจจุบันในลูป message.direction ปัญหาเดียวกับสิ่งนี้คือข้อความสุดท้ายในลูป messages[i+1] จะเป็น undefined และนี่คือจุดที่การตรวจสอบ or || isLast เข้ามา เพราะสิ่งนี้จะเป็นจริงเสมอสำหรับข้อความสุดท้ายในลูป เอกสารสำหรับ ngClass

นอกเรื่องหน่อย, messages[i+1] && messages[i+1].direction คุณจำเป็นต้องทำแบบนี้เพื่อให้สามารถตรวจสอบเงื่อนไข direction เฉพาะเมื่อ messages[i+1] ถูกกำหนด มิฉะนั้นโค้ดของคุณจะล้มเหลวเมื่อถึงรายการสุดท้าย คุณสามารถอ่านเพิ่มเติมเกี่ยวกับเรื่องนี้ได้ในเอกสาร Javascript

สำหรับการแสดง/ซ่อนอวาตาร์ นั่นเป็นเพียง CSS ง่าย ๆ เมื่อคุณมีคลาส last อยู่ในนั้น

นี่คือตัวอย่างที่ทำงานได้: https://stackblitz.com/edit/angular-gwqqee

หวังว่านี่จะช่วยได้นะ

แก้ไข: ฉันลืมไปว่าคุณมีผู้ใช้มากกว่าสองคน แต่แนวคิดเหมือนเดิม แค่ตรวจสอบ user_id แทนทิศทาง ดูตัวอย่างที่อัปเดตแล้ว

[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
  }"