3

Full source code: https://github.com/tenzan/menu-ui-tw

Demo: https://flamboyant-euclid-6fcb57.netlify.com/

Goal:

ItemsList and ItemImage are child components to Menu.vue. I need to pass the image_url from ItemsList to ItemImage, in order to change the image on right, after item on left is changed automatically on time intervals.

  • Left side: component ItemsList.vue
  • Right side: component ItemImage.vue

enter image description here

Component Menu.vue has 2 child components:

<template>
  <div>
    <!-- Two columns -->
    <div class="flex mb-4">
      <div class="w-1/2 bg-gray-400">
        <ItemsList />
      </div>
      <div class="w-1/2 bg-gray-500">
        <ItemImage></ItemImage>
      </div>
    </div>
  </div>
</template>

<script>
import ItemsList from "./ItemsList";
import ItemImage from "./ItemImage";

export default {
  components: {
    ItemsList,
    ItemImage
  }
};
</script>

ItemsList.vue:

<template>
  <div>
    <div v-for="item in menuItems" :key="item.name">
      <ul
        class="flex justify-between bg-gray-200"
        :class="item.highlight ? 'highlight' : ''"
      >
        <p class="px-4 py-2 m-2">
          {{ item.name }}
        </p>
        <p class="px-4 py-2 m-2">
          {{ item.price }}
        </p>
      </ul>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      menuItems: [
        {
          name: "Apple",
          price: 20,
          image_url: "../assets/images/apple.jpg"
        },
        {
          name: "Orange",
          price: 21,
          image_url: "../assets/images/orange.jpg"
        },
        {
          name: "Banana",
          price: 22,
          image_url: "../assets/images/banana.jpg"
        },
        {
          name: "Grape",
          price: 23,
          image_url: "../assets/images/grape.jpg"
        }
      ]
    };
  },
  created() {
    var self = this;
    self.menuItems.map((x, i) => {
      self.$set(self.menuItems[i], "highlight", false);
    });
    var init = 0;
    setInterval(function() {
      if (init === self.menuItems.length) {
        init = 0;
      }
      self.menuItems[init].highlight = true;
      if (init === 0) {
        self.menuItems[self.menuItems.length - 1].highlight = false;
      } else {
        self.menuItems[init - 1].highlight = false;
      }
      init++;
    }, 2000);
  }
};
</script>

<style scoped>
.highlight {
  background-color: gray;
}
</style>

ItemImage.vue - almost empty

<template>
  <div><p>Hello from ItemImage component</p></div>
</template>

<script>
export default {
  props: ["image_url"]
};
</script>

ItemsList iterates through each item and highlights it. I will need component ItemImage to show an image for that active/highlighted item. URL for an image is item.image_url .

nyagolova
  • 1,731
  • 2
  • 26
  • 42
Askar
  • 5,784
  • 10
  • 53
  • 96

2 Answers2

4

Emit an event in ItemsList component with image_url and in Menu component pass image_url to ItemImage component as a prop. I did this in below codesandbox check it out.

https://codesandbox.io/s/wild-moon-mbto4

Lucifer
  • 1,069
  • 4
  • 16
  • 26
2

You can try with emitting an event from the child to the parent component.

In your child component ItemsList.vue, emit an event to the parent component (where the highlight property is set to true):

created() {
    var self = this;
    self.menuItems.map((x, i) => {
      self.$set(self.menuItems[i], "highlight", false);
    });
    var init = 0;
    setInterval(function() {
      if (init === self.menuItems.length) {
        init = 0;
      }
      self.menuItems[init].highlight = true;
      
      //emit an event to trigger parent event
      this.$emit('itemIsHighlighted', menuItems[init].image_url)
      
      if (init === 0) {
        self.menuItems[self.menuItems.length - 1].highlight = false;
      } else {
        self.menuItems[init - 1].highlight = false;
      }
      init++;
    }, 2000);
  }

Then in your parent component Menu.vue:

<ItemsList @itemIsHighlighted="onItemHighlighted"/>
<ItemImage :image_url="this.selectedItem" ></ItemImage>

...

export default {
    data() {
        return {
            selectedItem: '' 
        } 
    }, 
    methods: {
        onItemHighlighted(value) {
            console.log(value) // someValue
            this.selectedItem = value
        }
    }
}

I couldn't test it, but I hope it helps.

You can also check this answer here.

P.S. Using Vuex would make this task a lot easier.

tony19
  • 125,647
  • 18
  • 229
  • 307
nyagolova
  • 1,731
  • 2
  • 26
  • 42
  • Thanks. I can't test at the moment, but I won't be clicking. I see you mentioned a @click event... – Askar Jan 22 '20 at 09:39
  • 1
    Sorry, I didn't realize that the rows are selected on time intervals. Then you just have to put the emitting event in the `setInterval()` function, where the property `highlight` is set to `true`. I updated my answer. – nyagolova Jan 22 '20 at 11:40