0

I have elements that are rendered using v-for Each element consist of text and button I need to show a button only if text is overflow div's height

<div v-for="el in elements" :key="el.id">
    <span>{{ el.text }}</span>
    <button>Click me</button>
</div>

Evident solution is use v-if, but what should I based on? I need to calculate height of text and decide to show button or not So I need refs for divs and function to determine show or not:

<template>
    <button @click="addDiv"> Click to add div </button>
    <div v-for="(el, index) in elements" :key="el.id">
        <span ref="items">{{ el.text }}</span>
        <button v-if="showButton(index)">Click me</button>
    </div>
</template>

<script setup lang="ts">
//imports
const elements = ref([]);
const addDiv = function() { 
    elements.value.push({ text: "Test", id: Date.now() })
}
const items = ref();
const showButton = function (index) {
    const item = items.value[index] as HTMLElement;
    return item.scrollHeight > item.offsetHeight
}
</script>

But I found the issue is that items are not synchronous with DOM. So it is clear why, DOM is updated asynchronously and that's why my data is a little bit late So I decided to add nextTick() in my showButton function, but it started to return Promise, which leads to v-if always true

<template>
    <button @click="addDiv"> Click to add div </button>
    <div v-for="(el, index) in elements" :key="el.id">
        <span ref="items">{{ el.text }}</span>
        <button v-if="showButton(index)">Click me</button>
    </div>
</template>

<script setup lang="ts">
//imports
const elements = ref([]);
const addDiv = function() { 
    elements.value.push({ text: "Test", id: Date.now() })
}
const items = ref();
const showButton = function (index) {
    nextTick(() => {
        const item = items.value[index] as HTMLElement;
        return item.scrollHeight > item.offsetHeight
    })
}
</script>

So is there any way to show or not my button for each element specifically?

DarT ALex
  • 3
  • 2
  • Does this answer your question? [Determine if an HTML element's content overflows](https://stackoverflow.com/questions/143815/determine-if-an-html-elements-content-overflows) – Core972 May 22 '23 at 10:13
  • Is is about element which is already on the page. But in my case elements are created with the button, so I don't think that is the answer. MoreOver there is no trouble to check overflowing, the trouble is to use v-if – DarT ALex May 22 '23 at 10:18
  • @DartAlex in my eyes you mixed up between serverside js (vue) and clientside js. The provided link uses clientside javascript. – Reporter May 23 '23 at 09:00

1 Answers1

1

I did it using the watchers in Vue, I hope it will help you !

<template>
  <button @click="addDiv">Click to add div</button>
  <div
    v-for="el in elements"
    :key="el.id"
  >
    <span ref="items">{{ el.text }}</span>
    <button v-if="el.showButton">Click me</button>
  </div>
</template>   

and the script, I've updated the typing part:

<script setup lang="ts">
  //imports
  import { ref, watch } from 'vue';

  const elements = ref<Array<any>>([]);
  const items = ref<Array<HTMLElement>>([]);

  const addDiv = function () {
    elements.value.push({ text: 'Test', id: Date.now(), showButton: false });
  };

  watch(items.value, (newItems) => {
    console.log('items changed');
    let cpt = 0;

    // you can do it with a for loop too
    newItems.forEach((item) => {
      if (item.scrollHeight > item.offsetHeight) {
        console.log('overflow -> show button');
        elements.value[cpt].showButton = true;
      }
      cpt++;
    });
  });
</script>
Samuel
  • 464
  • 5