In search of inspiration to create a recipient list similar to Gmail using Vue3?

Recently, I've been trying to create a recipient list similar to that in Gmail using Vue3 but I'm stuck and unable to find helpful resources online.

recipient list

I have an array of email addresses that I can loop through and display in a div. However, I'm unsure how to determine when an email reaches the end of the div so I can remove it.

In addition, I would like to show a badge indicating the number of hidden emails. The badge should only appear if all emails do not fit within the container box.

Your guidance on this matter would be greatly appreciated!

As of now, I haven't attempted any solutions because I'm uncertain where to even begin with this task. Should I calculate the width of the container div? And if so, how can I determine when a child div holding an email has reached its parent's end?

Answer №1

Initially, the email container's width is measured. Subsequently, each email element is measured whenever there's a change in the email array or browser width. By using slice(), the email array is adjusted to make sure sliced emails fit within the email container div.

You can test this example that I have created:

const app = Vue.createApp({
  data() {
    return {
      emails: [],
      renderedEmails: [],
      hiddenCount: 0,
    }
  },
  methods: {
    measureRecipientList() {
      const tolerance = 50
      const containerWidth =
        document.getElementById('email-container').offsetWidth + tolerance
      let totalWidth = 0
      let countDisplay = -1
      setTimeout(() => {
        const hiddenEmailDivs =
          document.getElementsByClassName('hidden-email')
        for (const el of hiddenEmailDivs) {
          if (totalWidth < containerWidth) {
            totalWidth += el.clientWidth
            countDisplay += 1
          }
        }
        if (totalWidth > containerWidth) {
          countDisplay -= 1
        }
        this.renderedEmails = this.emails.slice(0, countDisplay)
        this.hiddenCount = this.emails.length - countDisplay
      })
    },
    onWidthChange() {
      this.measureRecipientList()
    }
  },
  mounted() {
    window.addEventListener("resize", this.onWidthChange);
    setTimeout(() => {
      this.emails = [
        '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="50353d31393c61103528313d203c357e333f3d">[email protected]</a>',
        '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="60050d01090c52200518010d100c054e030f0d">[email protected]</a>',
        '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="fc99919d9590cfbc99849d918c9099d29f9391">[email protected]</a>',
        '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="147179757d782054716c75796478713a777b79">[email protected]</a>',
        '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="02676f636b6e3742677a636f726e672c616d6f">[email protected]</a>',
        '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="96f3fbf7fffaa0d6f3eef7fbe6faf3b8f5f9fb">[email protected]</a>',
        '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="12777f737b7e2552776a737f627e773c717d7f">[email protected]</a>',
        '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="442129252d287c04213c25293428216a272b29">[email protected]</a>',
        '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="ee8b838f8782d7ae8b968f839e828bc08d8183">[email protected]</a>',
        '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="e2878f838b8ed3d2a2879a838f928e87cc818d8f">[email protected]</a>',
      ]
    }, 500) 
  },
  unmounted() {
    window.removeEventListener("resize", this.onWidthChange);
  },
  watch: {
    emails() {
      this.measureRecipientList()
    },
  },
})
app.mount("#app")
#email-container {
  border: 1px solid #ccc;
  padding: 2px;
  height: 25px;
  white-space: nowrap;
  position: relative;
  overflow-x: hidden;
}

.email {
  opacity: 1;
  display: inline-block;
  border: 1px solid #ccc;
  background-color: pink;
  padding: 2px 2px;
  border-radius: 6px;
}

.hidden-email {
  visibility: hidden;
  display: inline-block;
  border: 1px solid #ccc;
  background-color: pink;
  padding: 2px 2px;
  margin-right: 2px;
  border-radius: 6px;
}

#badge {
  background-color: red;
  color: white;
  position: absolute;
  right: 0;
  top: 0;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100px;
}
<div id="app">
<div>Recipient List:</div>
  <div id="email-container">
    <div class="email" v-for="(email, index) in renderedEmails" :key="index">
      {{ email }}
    </div>
    <div class="hidden-email" v-for="(email, index) in emails" :key="index">
      {{ email }}
    </div>
    <div id="badge">
      {{ hiddenCount }} more
    </div>
  </div>  
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.4.8/vue.global.min.js"></script>

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

I need help figuring out how to set the country code as uneditable and also display a placeholder in react-phone-input-2 with React

How can I display the placeholder after the country code without allowing it to be edited? Currently, it's not showing up in my React functional components. Here is the code snippet: <PhoneInput className="inputTextDirLeft" ...

What is the process for linking dynamic content to document-ready events?

When it comes to jQuery and JavaScript, I admittedly struggle a bit. I have a specific question but can't seem to find the right search terms to get me there. It involves using either .trigger() or on(), but I'm unsure of the correct implementati ...

Unlimited scrolling: Fetching additional data via an Ajax request?

I am working on setting up a table with infinite scroll functionality to showcase user information such as name, address, and email. To accomplish this, I began by importing the json-server package and creating an API endpoint using fakerjs in a separate f ...

Determine the row index by identifying the row id and table id

I need to retrieve the Index number of a row when a hyperlink is clicked, while also passing additional data from this tag. <a href="javascript:void(0);" onclick="EditDoctorRow(' + RowCountDoctorVisit + ');"> <i class="fa fa-edit"&g ...

Experiencing problems with integrating Slim framework and AngularJS, such as encountering a 404 error

Although this may seem like a repeat question, I am encountering an issue with using AngularJS with Slim Framework web services. I have set up a webservice to retrieve a student record with a URL structure like: http://www.slim.local/api/getstudent/1 ...

Angular Build Showing Error with Visual Studio Code 'experimentalDecorators' Configuration

Currently experiencing an issue in VSC where all my typescript classes are triggering intellisense and showing a warning that says: "[ts] Experimental support for is a feature that is subject to change in a future build. Set the 'experimentalDeco ...

Issue with retrieving the current location while the map is being dragged

How can I retrieve the current latitude and longitude coordinates when the map is dragged? I've tried using the following code: google.maps.event.addListener(map, 'drag', function(event) { addMarker(event.latLng.lat(), event.la ...

Ensuring payload integrity using microrouter: A step-by-step guide

I have utilized this code to develop a microservice const { json, send } = require('micro') const { router, post } = require('microrouter') const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY) console.log(process.e ...

The initial number is inserted within the text box upon entering the final number

Whenever I enter the final digit, the text-box swallows up the initial number (it vanishes), resulting in an additional space. https://i.stack.imgur.com/Vfm8s.png https://i.stack.imgur.com/od4bQ.png Upon clicking outside of the text-box, the formatting ...

Is it possible to refresh data efficiently using web scraping tools, similar to how it

While researching web scraping in Python, I consistently found references to BeautifulSoup and Selenium as the primary tools for retrieving HTML and JavaScript content from websites. One thing that has eluded me is finding a method to automatically update ...

Ways to effectively manage multiple asynchronous operations while retrieving emails and attachments using IMAP and JavaScript

Currently, I am utilizing the IMAP library along with JavaScript to retrieve emails from a server. This is my approach: Retrieve emails based on email address, subject, and a specified time frame. Determine the total number of emails received. For each e ...

Highcharts integration with YQL finance data in JSON format

Currently, I am utilizing jQuery and highcharts.js to develop a single line chart on my website that displays historical financial data for any company specified by the user. I have been experimenting with YQL and employed this query to fetch some quotes i ...

JavaScript encountered an issue while parsing XML: the format is not well-formed

I keep seeing an error message saying "Error parsing XML: not well-formed" when I encounter this line in my javascript code: for (var i=1; i<=totalImgs; i++) If I remove the < character from the line, the parsing error goes away. However, the javas ...

Generic partial application fails type checking when passing a varargs function argument

Here is a combinator I've developed that converts a function with multiple arguments into one that can be partially applied: type Tuple = any[]; const partial = <A extends Tuple, B extends Tuple, C> (f: (...args: (A & B)[]) => C, ...a ...

Can the mui dialog actions button be activated using CTRL + S?

Is it feasible to enable my users to save content in a MuI dialog by pressing CTRL + S? ...

Error: Unexpected end of input detected (Likely due to a missing closing brace)

I've been struggling with this bug for the past two days, and it's driving me crazy. I have a feeling that I missed a brace somewhere in my script, but despite running various tests, I can't seem to pinpoint the glitch. Hopefully, your eyes ...

How to Animate an Object's Rotation Gently using React Three Fiber App and Use Cannon Library?

I am currently working on a project to create a Tetris-like game using React app, react-three-fiber, and use-cannon. I would like to implement a feature where objects/meshes rotate smoothly when clicked. How can I achieve this? Here is the code for the ob ...

Discovering WebElements nested within other WebElements using WebdriverJS

Looking at this HTML structure <div> <div> <p class="my-element"></p> </div> <div> <div> <div> <p class="the-text"> I want to retrieve this text</p> </div> </div> <div> ...

Issues with Pusher integration in Vue.js and Laravel API causing functionality to fail

Struggling with my Vue SPA and Laravel integration, I've spent hours searching online and trying various solutions to no avail. Here is the snippet from my index.html: <meta name="csrf-token" content="{{ csrf_token() }}"> Below is the subscri ...

Transform the API response array into a different format, ready to be passed as a prop to a

Looking to incorporate the Vue Flipbook component into my project, which requires an array of image URLs for the "pages" prop. I am fetching post responses from the WordPress REST API. My goal is to extract the "image" property from the response array and ...