0

I have an array. Inside that array I need to display the random component. In my case it's FeedbackComponent. It should be displayed before the last two objects in array. So it should be something like this schematically:

storyObject storyObject storyObject storyObject storyObject feedbackComponent storyObject storyObject

What is the way to show that component inside the list without mutating the array ? I've been looking for something that is available in React like rendering inside component.

So here's my PortfolioComponent.vue that consists of the few objects (that is stored in json data)

<template>
    <ul class="portfolio">
        <story-component
          v-for="story in portfolio"
          :key="story.id"
          :story-name="story.name"
          :story-title="story.title" />
        <li is="feedback-component" class="portfolio__feedback"></li>
    </ul>
</template>

<script>
import portfolio from '@assets/data/portfolio.json';

import StoryComponent from './StoryComponent';
import FeedbackComponent from './FeedbackComponent';

export default {
  components: {
    StoryComponent,
    FeedbackComponent,
  },
  data() {
    return {
      portfolio,
    };
  },
};
</script>

Here's html of my StoryComponent.vue

<template>
  <li class="story">
    <span class="story__name">{{ storyName }}</span>
    <span class="story__title">{{ storyTitle }}</span>
  </li>
</template>

Hope that's enough and I've explained that clear.

2 Answers2

0

You can use computed properties to slice your array at two parts:

<template>
    <ul class="portfolio">
        <story-component
          v-for="story in computedPortfolioBefore"
          :key="story.id"
          :story-name="story.name"
          :story-title="story.title" />

        <li is="feedback-component" class="portfolio__feedback"></li>

        <story-component
          v-for="story in computedPortfolioAfter"
          :key="story.id"
          :story-name="story.name"
          :story-title="story.title" />
    </ul>
</template>

<script>
import portfolio from '@assets/data/portfolio.json';

import StoryComponent from './StoryComponent';
import FeedbackComponent from './FeedbackComponent';

export default {
  components: {
    StoryComponent,
    FeedbackComponent,
  },
  computed: {
    computedPortfolioBefore() {
     if( this.portfolio.length > 2 ) {
       // returns all items except last 2
       return this.portfolio.slice(0, -2);
     } else {
       return this.portfolio;
     }
    },
    computedPortfolioAfter() {
     if( this.portfolio.length > 2 ) {
       // returns last 2 items
       return this.portfolio.slice(-2);
     } else {
       return [];
     }
    }
  },
  data() {
    return {
      portfolio,
    };
  },
};
</script>
tony19
  • 125,647
  • 18
  • 229
  • 307
fiter
  • 743
  • 1
  • 12
  • 25
0

You should just be able to use the index from the v-for to insert the extra component in the right place. The key line here is v-if="index === Math.max(0, portfolio.length - 2)". It's unclear what the correct behaviour should be if there are fewer than 2 items in the array, so I've assumed that the feedback component should go at the start in that case. If the array is empty then nothing will be rendered, so that case would need to be handled separately.

new Vue({
  el: '#app',
  
  data () {
    return {
      portfolio: [
        { id: 1 },
        { id: 2 },
        { id: 3 },
        { id: 4 },
        { id: 5 },
        { id: 6 }
      ]
    }
  }
})
<script src="https://unpkg.com/vue@2.6.10/dist/vue.js"></script>

<div id="app">
  <ul>
    <template v-for="(story, index) in portfolio">
      <li 
        v-if="index === Math.max(0, portfolio.length - 2)"
        key="feedback"
      >
        Feedback component
      </li>
      <li :key="story.id">
        Story component {{ story }}
      </li>
    </template>
  </ul>
</div>

I've just used plain <li> elements here but it would work just the same with components.

skirtle
  • 27,868
  • 4
  • 42
  • 57