In Vue, it is not accurate to measure overflow

I am working on creating an overflow effect with tagging that fades out at the beginning to provide a subtle hint to users that there is more content. Here is what it currently looks like:

https://i.stack.imgur.com/fXGBR.png

To achieve this, I added a fading gradient as a :after element in the CSS and "activated" it using Vue's style binding when scrollWidth > offsetWidth (indicating overflow bigger than the box itself).

However, I have encountered a problem where the calculation sometimes lags and does not accurately determine the scrollWidth, especially when entering a long word and then deleting it. In such cases, even though there is no tag remaining in the box, the overflow status is still falsely indicated. This behavior can be seen here: https://i.stack.imgur.com/yVhhd.png

I attempted to address this issue by placing the calculation inside a $nextTick(), but it did not resolve the problem. Additionally, I tried implementing Vue's keyDown, keyUp, and keyPress listeners, all to no avail.

A demonstration of this issue can also be viewed on CodePen.

Here is the code snippet showcasing the problem:

new Vue({
  el: '#tagsinput',
  data: {
    input_value: "",
    tags: []
  },
  methods: {
    addTag: function() {
      if (this.input_value > "") {
        this.tags.push(this.input_value)
        this.input_value = "";

        // Refocus the text input, so it stays at the end
        this.$refs.input.blur();
        this.$nextTick(function() {
          this.$refs.input.focus();
        })

      }
    },
    deleteTag: function() {
      if (this.input_value == "") {
        this.tags.pop()
      }
    }
  }
})
.outter {
  border: 1px solid red;
  width: 250px;
  overflow: hidden;
  display: flex;
}

.inner {
  border: 1px solid blue;
  margin: 2px;
  display: flex;
}

.tag {
  border: 1px solid black;
  margin: 2px;
}

input {
  min-width: 80px;
  width: 80px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.2/vue.min.js"></script>
<div id="tagsinput">
  <div class="outter" ref="outter">
    <div class="inner" ref="inner">
      <div class="tag" v-for="tag in tags">{{tag}}</div><input type="text" v-model="input_value" @keydown.enter="addTag" @keydown.delete="deleteTag">
    </div>
  </div>
  Outter div scrollwidth: {{ $refs.outter ? $refs.outter.scrollWidth : null }}<br> Outter div offsetWidth: {{ $refs.outter ? $refs.outter.offsetWidth : null }}<br>
  <br> Is overflowing: {{ ($refs.outter ? $refs.outter.scrollWidth : null) > ($refs.outter ?$refs.outter.offsetWidth : null) }}
</div>
<br><br> Type a really long word in, add and then delete it. "Is overflowing" will be the inverse, until you press Backspace <b>again</b>.

Any assistance with resolving this issue would be highly appreciated.

Answer №1

Make sure to check for overflow after adding or deleting a tag to ensure it happens at the right time. Vue does not bind inline conditions like that. Use the code below, which calls a function checkOverflow within $nextTick to set a data-bound variable isOverflowed for styling purposes.

new Vue({
    el: '#tagsinput',
    data: {
        input_value: null,
        tags: [],
        isOverflowed: false
    },
    methods: {
        addTag: function() {
            if(this.input_value) {
                this.tags.push(this.input_value)
                this.input_value = null;

                // Keep text input focused at the end
                this.$refs.input.blur();
                this.$nextTick(function() {
                    this.$refs.input.focus();
                    this.checkOverflow()
                })
            }
        },
        deleteTag: function() {
            if(!this.input_value) {
                this.tags.pop()
                this.$nextTick(function() {
                    this.checkOverflow()
                })
            }
        },
        checkOverflow: function() {
            this.isOverflowed = (this.$refs.outter ? this.$refs.outter.scrollWidth : null) > 
                (this.$refs.outter ? this.$refs.outter.offsetWidth : null)
        }
    }
})
.outter {
    border: 1px solid red;
    width: 250px;
    overflow: hidden;
    display: flex;
}

.inner {
    border: 1px solid blue;
    margin: 2px;
    display: flex;
}

.tag {
    border: 1px solid black;
    margin: 2px;
}

input {
    min-width: 80px;
    width: 80px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="tagsinput">
    <div class="outter" ref="outter">
        <div class="inner" ref="inner">
            <div class="tag" v-for="tag in tags">{{tag}}</div>
            <input type="text" v-model="input_value" @keydown.enter="addTag" @keydown.delete="deleteTag" ref="input">
        </div>
    </div>
    <br>
    Is overflowing: 
    {{ isOverflowed }}
</div>
<br><br>
Enter a long word, add it, then delete it. "Is overflowing" will change, reverse when you press Backspace <b>again</b>.

Answer №2

Here's a clever trick using CSS and HTML...

To create a fade effect, insert

<div id="spaceFade"></div>
right after <div id="tagsinput">. Then, add this CSS code:

#spaceFade {
  background-image: linear-gradient(to right, rgba(255,255,255,1), rgba(255,255,255,1), rgba(0,0,0,0));
  position: absolute;
  height: 2em;
  width: 3em;
}
#tagsinput {
  position: relative;
}
.outer {
  justify-content: flex-end;
}

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

Creating a mandatory 'Select' dropdown field in Vue.js

Hello, I am a beginner in VueJS and I am trying to make a select element from a drop-down list required. I attempted to add the required attribute as shown in the code below. Any suggestions on how to achieve this? Thanks. <v-select ...

How can I create a delay in the Nuxt-link transition to a new page

In continuation to issue #1458 on GitHub, I am seeking guidance on how Nuxt expects this situation to be managed. I have a menu that needs to close when a nuxt-link in the menu is clicked before the page transition occurs. However, I only want this behavi ...

Resolving issues with jQuery's live() method while incorporating AJAX calls

One of the challenges I'm facing is with buttons on a webpage that are part of the class "go". The code snippet below demonstrates how I handle actions related to these buttons: $(".go").live('click', this.handleAction); The issue arises w ...

Tips for ensuring a functioning dropdown menu while maintaining a fixed navigation bar position

I am facing an issue with my navigation bar. I have set the position to fixed to keep it at the top, but this is causing the drop-down functionality to stop working. Please advise on where I should move the position fixed property so that my nav bar remai ...

Maintaining datatype integrity in MongoDB Stitch when decrementing with update statements

Using a MongoDB Stitch function, I have two collections: communities and posts. Whenever a new document is inserted in the post collection, I need to increment the summary.postCount in the communities collection by +1. Similarly, when the status of a post ...

Express router is unable to process POST requests, resulting in a 404 error

I am having trouble fetching POST requests to my Express router. While my many GET requests work fine, this is my first POST request and it is not functioning correctly. Here is a snippet of my frontend code: export async function postHamster(name, age) ...

Comparison of HTML's equivalent to LaTeX's label and ef functionality

I have a Frequently Asked Questions page coded in HTML (example) where the questions often refer to one another. This results in the numbering changing whenever we add, delete, or rearrange the questions. LaTeX provides an elegant solution to this problem ...

Error with NEXTJS: Prop type failed - The prop `href` in `<Link>` is expecting a `string` or `object`, but received `undefined`

After importing the Link from next/link and attempting to pass the dynamic endpoint in my components, I encountered an error message. https://i.stack.imgur.com/eqUK8.png https://i.stack.imgur.com/eIC4V.png I searched for a solution and came across a sug ...

"Embracing Flexbox for a fully responsive mobile experience

What's the best way to make this flexbox design responsive for mobile devices? I want the layout to look consistent across both desktop and mobile screens. The issue seems to be related to the responsiveness of the flexbox and the smaller size of mobi ...

I'm looking to learn how to implement the delete method in an API using TypeScript. Can anyone help me out

I am seeking guidance on utilizing 'axios' within 'nuxt.js'. I have experimented with sample data, and I am particularly interested in learning how to utilize the 'axios' method within 'nuxt.js' using TypeScript. T ...

Is it possible to utilize localStorage.getItem within Next.js while using redux toolkit?

While I successfully used localStorage.setItem() inside the redux toolkit slice, I encountered an issue when trying to use localStorage.getItem(). The error message "local storage is not defined" popped up, preventing me from accessing the stored data. imp ...

React hitting recursion limit due to excessive shouldComponentUpdate checks

I'm currently developing a real-time updating dashboard using React. The data for the dashboard components is fetched via an Ajax call and then passed to each component successfully. However, I encountered an issue with one specific component that re ...

Inject the content loaded from the server into a div element, and insert that div at the

I am trying to insert the div(#loadmore) element inside the div(#boxchatting) element when the content from "result.php" is loaded into div(#boxchatting). Here is the code I used: $('#loadmore').prependTo('#boxchatting'); $('#boxc ...

After the "div" tag comes the magic of AJAX, PHP, and JAVASCRIPT, replacing

My Ajax implementation is successfully displaying the selected content on a div, but unfortunately, everything that comes after the div is getting replaced by this output. I am unsure of why this is happening and how to resolve it. If you have any insigh ...

Updating events instantly with a single click in Angular 6: A step-by-step guide

Hello there, I am currently diving into learning Angular 6 and I have encountered a query. I want to achieve a functionality where upon clicking a button, the text on the button changes as well as the corresponding event that triggers when the button is cl ...

The Owl carousel slide vanishes unexpectedly after resizing the window

My Owl-carousel slides are disappearing after resizing the browser window. You can see the issue in action here: . The website where this problem occurs is: . I suspect it has to do with the CSS animation within the items, as disabling the fade animation r ...

Updating a specific field in a document using Node.js and MongoDB

Hey, I'm a beginner in nodeJS and I could use some help. I've been able to update an entire document easily but I'm struggling to update just a single value. Here's my code: router.patch("/:id", async (req, res) => { console.log(re ...

What could be the reason for the empty response in my PATCH request in Javascript?

I am facing an issue with my app that runs Rails in the backend and Javascript in the frontend. The controllers, routes, and CORS are all set up correctly. Both my Post and Get requests work without any problems. However, when I attempt to make a patch req ...

Discovering the process of retrieving information from Firebase using getServerSideProps in NextJs

I've been exploring ways to retrieve data from Firebase within GetServerSideProps in NextJs Below is my db file setup: import admin from "firebase-admin"; import serviceAccount from "./serviceAccountKey.json"; if (!admin.apps.len ...

Enhancing the functionality of radio buttons through event changes and optimizing related features

I am searching for a more efficient method to reuse functions that serve a similar purpose. For example, I would like to modify various radio buttons that toggle a hide class on different divs. JSFiddle Link How can jQuery be used to create a reusable fu ...