0

It's been a while since using Vue JS and I am currently attempting to render a list of data with a button for each record. When the button is clicked, I would like to conditionally render a component ( in this instance).

Is there a Vue approved way of doing this? Should I be manipulating the DOM? The following doesn't seem to work.

<template>
    <div v-for="data in list">
      {{ data.bar}}
      <button @click="handleClick">
        <div v-if="dataset.loading === 'true'">
          <loader/>
        </div>
        <div v-else>
      </button>
    </div>
</template>

<script setup>
    import { loader } from './components'

    const list = [{ foo: 'bar'}];
    
    const handleClick = (el) => {
        el.dataset.loading = 'true';
        setTimeout(3, () => el.dataset.loading = 'false');
    };
</script>

2 Answers 2

1

Observation :

  • There is no object with bar key in the list array. Use data.foo instead of data.bar.

Suggestions :

  • It is recommended to provide a :key with v-for whenever possible.

  • Add loading property in each object of the list array. So that it will behave dynamically while setting the value onClick.

Live Demo :

new Vue({
  el: '#app',
  data: {
    list: [{ foo: 'bar', loading: false }]
  },
  methods: {
    handleClick(dataIndex) {
      this.list[dataIndex].loading = true;
      setTimeout(() => {
        this.list[dataIndex].loading = false;
      }, 2000);
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <div v-for="(data, index) in list" :key="index">
      {{ data.bar }}
      <button @click="handleClick(index)">
        <div v-if="data.loading">
          Loading Start
        </div>
        <div v-else> Loading Finish </div>
      </button>
    </div>
</div>

Sign up to request clarification or add additional context in comments.

3 Comments

The list of data will be coming from an ajax request. The signature of those objects will not contain a loading attribute. Are you suggesting I apply that property via Array.map or is there another way?
@Query Instead of Array.map, you can add that property via Array.forEach() with default value as false.
@Query did you tried that ?
0

You need to use ref on your list variable to make it reactive. Also, you are accessing a dataset variable which doesn't exists in your application.

This is one way of doing it, I just added an extra data on your list


<script setup>
import {ref} from 'vue'


let list = ref([{ foo: 'bar', loading: 'true'}]);

const handleClick = (data) => {
    setTimeout(() => {
      data.loading = 'false'
    },1000);
};

</script>

<template>

    <div v-for="data in list" >
      {{ data.foo}}
      <button @click="handleClick(data)"> //you can also use a `ref` here.
        <div v-if="data.loading === 'true'">
          Your Loader Component
        </div>
        <div v-else> 
          Something else...
        </div>
      </button>
    </div>
</template>

You can also use Template Refs

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.