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

Encountering the "Error: data.map is not a function" issue within Next.js

I'm having trouble understanding why this first fetch call works perfectly: async function getData() { const res = await fetch('https://jsonplaceholder.typicode.com/todos') return res.json() } export default async function Home() { co ...

Dropdown element vanishes upon selecting in HTML

Utilizing Angular's ng-init to populate a rest call function and populate $scope.races before filling up the dropdown. Initially, everything appears to be working correctly. However, upon selecting an option from the dropdown menu, it immediately cle ...

Having trouble getting accurate data from the TimePicker Form in Vue

Currently, I am delving into the realm of Laravel and Vue. However, I have encountered a perplexing issue with a form. Specifically, I have integrated a timepicker from this source (https://github.com/MatijaNovosel/vue-material-time-picker) for determining ...

Customize time formatting in Angular to accommodate localized time formats

I am utilizing Angular's localization service version 8.3.28 to support English, Spanish (Mexico) with code es-MX, and Spanish (Spain) with code es-SP While using the date pipe: {{ foo.Date | date: 'shortDate' }} The dates are changing to ...

Express.js experienced a 404 error when processing POST requests

When working with js and express, the route handler file looks like this: var express = require('express'); var passport = require('passport'); var authRoutes = App.route('authRoutes'); va ...

Is there a way to determine if the current path in React Router Dom v6 matches a specific pattern?

I have the following paths: export const ACCOUNT_PORTAL_PATHS = [ 'home/*', 'my-care/*', 'chats/*', 'profile/*', 'programs/*', 'completion/*', ] If the cur ...

Struggling to get the ReactJS.NET MVC tutorial to function properly?

After deciding to start a new project in Visual Studio with MVC 5 and a single page app using ReactJS, I consulted the guide on the ReactJS website. Upon running the project for the first time, I encountered a syntax error due to JSX. It seemed that the b ...

Discovering the specific URL of a PHP file while transmitting an Ajax post request in a Wordpress environment

I'm currently working on a WordPress plugin and running into some issues with the ajax functionality. The main function of my plugin is to display a form, validate user input, and then save that data in a database. Here is the snippet of code for my ...

Enabling clients to access all static files from a Node.js + Express server

My index.js file serves as a node.js server : var express = require('express'); var app = express(); const PORT = process.env.PORT || 5000; var serv = require('http').Server(app); app.get('/', function(req, res) { res.sen ...

Validate input strings in Node.js using Joi to detect and return an error if there are leading or trailing spaces

Looking to set up JOI validation in Node.js that flags errors if a string begins or ends with an empty space. For example: name = "test123" //valid name = "test(space)" or "(space)test" // invalid ...

Error: Unable to render followers list due to incorrect data type

I have embarked on creating a unique Github user card generator that retrieves user data and their followers' information from the GitHub API, then displays them on a personalized user card. The follower's data received is in the form of an array ...

Using VueJs, create a dynamic css class name to be applied inline

Can VueJs handle a scenario like this? Html: <div class="someStaticClass {{someDynamicClass}}">...</div> JS: var app = new Vue({ data: { someDynamicClass: 'myClassName' }, mounted: function() { ...

Java method to transform a two-dimensional char array into a one-dimensional int array

Currently, I am attempting to create a Java method that will convert an array of characters[][] which are each associated with an integer array[] into an array of integers: public static int charArrayToInt (char[][] Grades, int[] studentList) { int[] ...

Tips for saving a JavaScript object into a JSON file

Let's discuss how to save the following data: myJSONtable into a JSON file using the following method: fs.writeFile('./users.json', JSON.stringify(myJSONtable, null, 4), 'utf-8', function (err) { if (err) throw err ...

Cache for AngularJS $http.jsonp requests

I'm struggling with caching a JSONP request and have tested out different approaches without success. I attempted $http.jsonp(url, { cache: true }) and $http({ method: 'JSONP', url: url, cache: true }), but neither worked as expected. As a ...

Is there a more efficient method for transferring data between dynamically loaded components?

My recent project involved creating a small application using Vue.js and Express.js. To prepare the necessary components from the server, such as the combobox for Article.Category and Article.User, I needed to render options from the server. I utilized < ...

Working with Angular to add various items to an array based on multiple conditions

Currently, I am a beginner in TypeScript and currently involved in an Angular project. As part of my work, I need to make an API call and perform various operations on the received data: public data_Config: IConfig[] = []; this.getService.Data(input).sub ...

Converting the AppDelegate.m file to AppDelegate.mm and updating the AppDelegate.h file during the transition from React Native 0.66.4 to 0.71.3

Original code in AppDelegate.h: #import <React/RCTBridgeDelegate.h> #import <UIKit/UIKit.h> #import <UserNotifications/UserNotifications.h> @interface AppDelegate : UIResponder <UIApplicationDelegate, RCTBridgeDelegate, UNUserNotificat ...

Ionic, Angular - A component with two out of three inputs displaying undefined values

I am facing an issue with the @input() in my code. Two out of three inputs have undefined values when I try to use them, although they can be displayed using interpolation in the template file. .ts : export class NoteCanvasPageComponent { @Input() note ...

Convert matrix into a three-dimensional array following a particular sequence

I am struggling to convert a 2D matrix into a 3D array in a specific order. While this may seem like a simple task, I have been unable to find the correct method to achieve it. X Y [1,] 276.9421 0.0000000 [2,] 276.4248 -5.3750000 ...