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>
[class]="message.direction"
นี่จะแจ้งทิศทางของข้อความให้เราเป็นคลาส me หรือ others ในกรณีของคุณ ค่อนข้างตรงไปตรงมา
ตอนนี้ให้ฉันอธิบายส่วนของชั้นเรียน 'สุดท้าย':
*ngFor="let message of messages; let isLast = last; let i = index;"
คำสั่ง ngFor จะเปิดเผยตัวแปรท้องถิ่นบางตัว เช่น last, first, index ดังนั้นเราสามารถใช้ประโยชน์จากสิ่งนั้นและกำหนดตัวแปร isLast ของเราให้กับตัวแปรท้องถิ่น last จากลูป ngFor พร้อมกัน ตัวแปร i ของเราจะเก็บค่า index ปัจจุบันของลูป ngFor เอกสารสำหรับ ngFor
[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
}"


