[Vuejs]-How can I make a message inside a v-for only appear once, if any of the items meets a certain condition?

0👍

  1. You don’t need the v-for
  2. You need a computed checking if items’ dates include current date, along these lines:
  computed: {
    showMessage() {
      return this.items.map(({ date }) => date).includes(this.currentDate)
    }
  }

Note: your computed would have worked too if it evaluated equality (==) or strict equality (===), instead of assigning (=) 1.

  1. Use in template as
<div v-if="showMessage">your message</template>
  1. Last, but not least, don’t reset/init items with null. Use an empty array ([]). This way the array methods (.some(), .includes()) are still available when data is not present.

Working demo 2:

const fromRange = (min, max) => Math.random() * (max - min) + min
const toDateString = (date = new Date()) => date.toJSON().slice(0, 10)
const getRandomDate = (date = new Date()) => (
  date.setDate(date.getDate() + fromRange(-5, 5)), toDateString(date)
)
const getItems = () =>
  Promise.resolve(
    Array.from({ length: fromRange(3, 12) })
      .map(getRandomDate)
      .map((date) => ({ date }))
  )

new Vue({
  data: () => ({
    items: [],
    currentDate: toDateString()
  }),
  mounted() {
    this.load()
  },
  computed: {
    showMessage() {
      return this.items.map(({ date }) => date).includes(this.currentDate)
      /* or:
      return this.items.some(({ date }) => date === this.currentDate) 
      // */
    },
    isLoading() {
      return !this.items.length
    }
  },
  methods: {
    load() {
      this.items = []
      setTimeout(async () => {
        this.items = await getItems()
      }, 1.2e3)
    }
  }
}).$mount('#app')
<script src="https://unpkg.com/vue@2/dist/vue.min.js"></script>
<div id="app">
  <div v-if="isLoading">Loading items...</div>
  <div v-else>
    <div v-if="showMessage">Show the message</div>
    <div v-else>not today. try again tomorrow.</div>
    <button @click="load">Refresh items</button>
  </div>
  <pre
    v-text="JSON.stringify({ dates: items.map(({ date }) => date), currentDate }, null, 2)"
  ></pre>
</div>

1 – This is quite important. You’re also assigning in the v-if:

<div v-if="item.date = currentDate">
  show some message
</div>

…meaning you assign currentDate to each of your items’ date, in the template, when the item gets rendered. Use v-if="item.date === currentDate" instead.
2 – Don’t mind the generators, they’re only mocking the backend call, and I chose to use dates directly instead of importing moment.

Leave a comment