How to conditionally close a <div> tag in Vue.js

My API is returning chat messages in a specific object format.

messages : [

    [
       sender: "John Doe",
       text: "Some message",
       sent_at: "2020-09-26",
       date_group: "Today",
    ],
    [
       sender: "John Doe",
       text: "Some message",
       sent_at: "2020-09-26",
       date_group: "Today",
    ],
    [
       sender: "John Doe",
       sent_at: "2020-09-26",
       date_group: "Today",
    ],
    [
       sender: "John Doe",
       text: "Some message",
       sent_at: "2020-09-25",
       date_group: "Yesterday",
    ],
    [
       sender: "John Doe",
       text: "Some message",
       sent_at: "2020-09-25",
       date_group: "Yesterday",
    ],
    [
       sender: "John Doe",
       text: "Some message",
       sent_at: "2020-09-24",
       date_group: "Thursday",
    ],
]

To display these messages according to their date_group, I have implemented a comparison function for the dates.

    printDateGroup(messageKey) {
        return this.messages[messageKey - 1] && this.messages[messageKey].date_group !== this.messages[messageKey - 1].date_group
            || messageKey === 0;
    },

While this method is effective, all messages are currently displayed within a single div, causing issues with the sticky positioning of the date_group.

The current rendering structure is as follows.

<div class="d-flex flex-column message-wrapper">
    <template v-for="(message, idx) in messages">
        <div v-if="printDateGroup(idx)" class="date-label">
            <span>{{ message.date_group }}</span>
        </div>
        <div class="message-text">{{message.text}}</div>
    </template>
</div>

However, I desire to organize the messages into separate divs based on their date_group, like so.

<div class="d-flex flex-column message-wrapper">
     <div class="date-wrapper">
         <div class="date-label">Yesterday</div>
         <div class="message-text">Some message</div>
         <div class="message-text">Some message</div>
         <div class="message-text">Some message</div>
     </div>
     <div class="date-wrapper">
         <div class="date-label">Today</div>
         <div class="message-text">Some message</div>
         <div class="message-text">Some message</div>
         <div class="message-text">Some message</div>
     </div>
</div>

I attempted to keep the divs open without closing them like in PHP, but it did not work as expected.

Answer №1

In Vue, it is not possible to achieve this directly, but you can restructure your data model.

Below is an example of a component that functions as required:

<template>
  <div class="d-flex flex-column message-wrapper">
    <template v-for="(group) in groups">
      <div class="date-wrapper">

        <div class="date-label">
          {{ group.name }}
        </div>
        <div v-for="message in group.messages" class="message-text">{{message.text}}</div>
      </div>
    </template>
  </div>
</template>

<script>
  export default {
    name: "index",
    computed: {
      messages() {
        return [
          {
            sender: "John Doe",
            text: "Some message",
            sent_at: "2020-09-26",
            date_group: "Today",
          },
          // more message objects...
        ]
      },
      groups() {
        const res = [];
        for (let i = 0; i < this.messages.length; i++) {
          if (this.printDateGroup(i)) {
            res.push({
              name: this.messages[i].date_group,
              messages: [this.messages[i]]
            })
          } else {
            res[res.length - 1].messages.push(this.messages[i])
          }
        }
        return res;
      }
    },
    methods: {
      printDateGroup(messageKey) {
        return this.messages[messageKey - 1] && this.messages[messageKey].date_group !== this.messages[messageKey - 1].date_group
          || messageKey === 0;
      },
    }
  }
</script>

This limitation arises from the design approach of Vue.

Data modeling responsibilities lie within JavaScript, while templates should focus on simpler operations like for loops or if statements, leaving more complex processing tasks to the JavaScript part of components.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Guide on how to programmatically assign a selected value to an answer using Inquirer

Currently, I'm utilizing inquirer to prompt a question to my users via the terminal: var inquirer = require('inquirer'); var question = { name: 'name', message: '', validation: function(){ ... } filter: function( ...

What is the best way to bring up the keyboard on an iPhone when focusing an HTML text field?

Currently working on developing a web app for iPhone, and looking to implement a feature where a text field is automatically focused upon page load, prompting the keyboard to appear. Despite attempting the standard Javascript method: input.focus(); I see ...

Is there an issue with the deletion feature in my API?

I'm currently enrolled in a web programming course where we are working on developing web server API's. I have successfully implemented the POST and GET methods, but I seem to be facing some difficulties with the DELETE method. I would really app ...

Avoiding the use of if statements in Javascript

I've recently started learning Javascript and I'm facing an issue with my code. I want to create a functionality where clicking on an image on one page redirects you to another page and shows a specific div based on the clicked image. To achieve ...

To maintain the width values (maximum width) when using overflow:auto, do not make any adjustments. (CSS for scrollbars

My English isn't the best and I'm just starting out with CSS. The scroll bar is taking up space and I want to prevent that from happening. I have noticed that when the scroll bar appears, it causes the fixed navigation menu bar to shift and the ...

What is the process of using TypeScript to import a constant exported in JavaScript?

In the environment I'm using typescript 2.6.1. Within react-table's index.js file, there is a declaration that looks like this: import defaultProps from './defaultProps' import propTypes from './propTypes' export const React ...

Starting Web Server using File (file://) protocol

I'm currently using Quasar to develop a Vue SPA web app/page. For this project, the web app will only run by clicking on the index.html file generated by the Quasar packager. This package will not be distributed online or hosted on any domain. My mai ...

Enhance your Vue.js application by dynamically adding a class when a computed value

Just delving into the world of vue.js and I have a simple query. I've been following a tutorial but now I'd like to add my own touch to it :-P Whenever there is a change in my rank, I would like to include a CSS class for animating the label. Ho ...

Transitioning from one CSS id to another during page loading

Wondering how to fade in one CSS id on page load and then smoothly transition to another after a few seconds? Here are the ids: #background { background: url("images/am_photography_bg.jpg") no-repeat center -25px fixed; background-size: 100%; ...

Including a cancel button to close the open window

var messagebox = Ext.widget("messagebox", { target: grid, progressMessage: "Loading" }); The message box displayed above indicates the loading progress bar that appears when the download button is clicked. I am looking to incorporate a cancel button i ...

When navigating to a new page in Vue.js, automatically scroll to the top of the view

I attempted to utilize this.$router.replace(…) within the router-link, however it does not appear to be effective. Is there a built-in Vue method for achieving the same functionality without relying on any external libraries? ...

Exploring the method of extracting data from a JSON response containing various objects

I am working with a REST API that returns multiple objects within a single JSON response. My goal is to extract specific data from all objects in the response using Python 2.7. How can I efficiently retrieve the "key", "name", and "emailAddress" for each ...

Each Vue.js component is intricately connected to one another, synergistically intertw

The behavior I expected from the component was for each one to be independent and display separate counters. However, it seems that this is not the case... Below is the HTML structure: <div id="app"> <counter> </counter> <counter ...

Guide to adding directional arrow indicators on the Y and X axes of a ChartJS graph

https://i.sstatic.net/ZKkXT.png Is it possible to add directional arrows on the Y and X axis of a ChartJS graph? I'm seeking advice or tips on how to achieve this. Below is the code snippet for creating the chart. var ctx = $("#mycanvas"); ...

There seems to be an issue with vue not properly refreshing the data on the esri

I have created a composable function called useEsriMap with the following code: export const useEsriMap = () => { const mapObject = ref() const esriObject = computed(() => mapObject.value.esriObject) const panTo = (lat, long) => { esriO ...

Is it possible to activate every function within a prototype?

When presented with a class structure as demonstrated below, I am able to iterate through all its PropertyNames using console.log. class Security { constructor(param: ParamType) { this.method1(param); ... this.methodN(param); } method1(p ...

What is the best way to trim a string property of an object within an array?

I am seeking a solution to access the "description" property of objects within an array and utilize a string cutting method, such as slice, in order to return an array of modified objects. I have attempted using for loops but have been unsuccessful. Here ...

Attempting to utilize JSON.Stringify on Scripting.Dictionary objects will result in failure

In my current ASP classic project, I have integrated the JScript JSON class available at this link. This class can interact with both VBScript and JScript, closely resembling the code provided on json.org. However, due to team manager's requirement, I ...

Creating a dynamic jstree from scratch

My goal is to dynamically generate a jstree when a button is clicked. The user will select the entities from the tree, and I want to display that tree in the selected tab in tree format. The code below works perfectly fine if I use the variable aka as it ...

Tips for Adding Items to an Infinite Loop

Could you please review This Demo and advise me on how to continuously load items into the ul list in an endless manner? Currently, I have this code set up to display the list but I want it to keep adding new items to the end every time. var item = $(". ...