cmp
cmp

Reputation: 452

How can I can show a div if an object doesn't have a value outside of the object scope

I have a small Nuxt issue that I can't work out how to get around.

Essentially, I have an object (used for a carousel slider).

<template>
  <div
    :class="[$style.swiperSlide, 'swiper-slide']"
    v-for="slide in slides"
    :key="slide.id">
    <nuxt-img
      :class="[$style.img]"
      :alt="slide.alt"
      :src="imgSources(slide)"
      sizes="sm:100vw"
    />
    <div :class="[$style.info, 'info-b']" v-if="slide.info">
      {{ slide.info }} 
    </div>
  </div>

  <button :class="[$style.infoOpen]" 
    @click="showTab" 
    v-if="slideInfoAvailable"
  >
    Close
  </button>
</template>

<script>
export default {
  props: {
    slides: {
      type: Array,
      required: true,
      default: () => []
    }
  },
  computed: {
    slideInfoAvailable() {
      return this.slide?.info
    }
  },
  mounted() {
    const swiper = new Swiper(".swiper-container", {
      . . .
    });
  },
  methods: {
    imgSources(slide) {
      return `/img${slide.imgPath}.jpg`;
    },
};
</script>

All works o.k, the problem is that I have a button outside of this v-for that I need to only be visible if there's slide.info but because this div is outside of the v-for it can't tell if it's available.

Cannot read property 'info' of undefined

The easiest way out of this is to add the button inside of the slider - but I can't for Z-index CSS issues. It has to be outside of the 'slider' div.

Any ideas how I can only show the button if there's slide.info? For some of my slides, there won't be.

<slider
  :slides="[
    {
      imgPath: '/demo',
      info: 'Demo info for this slide',
      alt: 'Homepage'
    },
     {
      imgPath: '/demo2',
      alt: 'Homepage'
    },
  ]"
/>

One way I could do it would be to see if .slide-active .style.info exists. If it doesn't exist then I can hide the button as slide-active is added to the active div by the slider API.

Upvotes: 1

Views: 84

Answers (1)

kissu
kissu

Reputation: 46677

The issue is coming from the fact that you probably have some async fetching and that slides are not available upon initial render. To prevent this, you can use a computed with some optional chaining like this

export default {
  computed: {
    slideInfoAvailable() {
      return this.slide?.info
    }
  }
}

Then, call it like this

<button :class="[$style.infoOpen]" @click="showTab" v-if="slideInfoAvailable">

You cannot use ?. directly in the template.

You could also do the classic way of

<button :class="[$style.infoOpen]" @click="showTab" v-if="slide && slide.info">

but it does not look as sexy IMO (but you do not need any computed).

And yeah, for this kind of thing, better to handle it with Vue than relying on some hacky dirty CSS tricks!

Upvotes: 2

Related Questions