2

I have a pretty simple implementation so I feel like this may be a silly question. Just starting with vue I am trying to make a component be able to list other components; kind of like a reusable List, Table, Grid, ect.

Parent component imports gridView as a normal component:

<template>
  <div :id="id" class="grid-view">
    <slot></slot>
  </div>
</template>

And then in another component I attempt to build this:

<grid-view :dataSource="items">
  <grid-view-item-test
    v-for="(item, index) in items"
    :key="index"
    :title="item.title"
  />
</grid-view>

And then grid-view-item-test is simple. title being a prop. Works completely fine standing alone or without the use of a slot, but I wanted to make grid-view reusable to just take whatever other component I add and display as-is.

<template>
  <div>
    <div>{{ title }}</div>
  </div>
</template>

If I were to do something like this:

<grid-view :dataSource="items">
   <grid-view-item-test
     :key="index"
     :title="'Test 1'"
   />
   <grid-view-item-test
     :title="'Test 2'"
   />
   <grid-view-item-test
     :title="'Test 3'"
   />
</grid-view>

It works completely fine. Am I doing the loop wrong? I can confirm the loop works to get the number of items correctly. If I make a default fallback on the slot - I get the correct number, and I have printed it directly outside of the grid-view component.

Is this not a possibility? If not, would you just use HTML instead of a component for a reusable table as that seems to work fine.

Edit:

It works completely fine if I use an of strings, or numbers, but not objects.

I've tracked it down to items being an empty array as a computed variable and then throwing TypeError: null is not an object (evaluating 'oldChildren[i]'). Can confirm that items begins empty, and then is populated once a database call sets it, but I'm guess I'm not able to do something like that with slots?

After more testing it fails when you update the dataSet (items) at all. Is re-rending not possible with slots like this?

It works flawlessly if I have an empty div (or anything) when there are no items in the initial array.

Torewin
  • 887
  • 8
  • 22
  • Sorry, I don't understand the question. What's the issue with this? – Daniel_Knights Mar 13 '21 at 19:46
  • @Daniel_Knights Added some more information under Edits as I continue to debug. Looks like it may be a limitation of Vue slots or a limitation of my understanding. – Torewin Mar 13 '21 at 20:23

1 Answers1

1

You probably should provide more a more accurate code because I don't see any problem with what you provided

Working example:

const gridView = Vue.component('gridView', {
  props: ['dataSource'],
  template: `
    <div class="grid-view">
      <h4>My grid</h4>
      <slot></slot>
    </div>
  `
})

const gridItem = Vue.component('grid-view-item-test', {
  props: ['title'],
  template: `
    <div>
      <div>{{ title }}</div>
    </div>
  `
})

const vm = new Vue({
  el: '#app',
  data: () => ({
    items: [{
        title: 'Test 1'
      },
      {
        title: 'Test 2'
      },
      {
        title: 'Test 3'
      },
    ]
  })
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <grid-view :data-source="items">
    <grid-view-item-test v-for="(item, index) in items" :key="index" :title="item.title" />
  </grid-view>
</div>
Michal Levý
  • 33,064
  • 4
  • 68
  • 86
  • After further investigation it seems to be caused by the data being a computed variable and coming from an async call to the database - `item` starts off as an empty array and then is populated. I am assuming Vue doesn't like having 0 items in the array and then updating it? – Torewin Mar 13 '21 at 20:18
  • Your problem has nothing to do with slots. If your `computed` is throwing an error after data was fetched from the server, then your array is still empty - nothing can render. The problem is in that computed prop (your code) ...not Vue – Michal Levý Mar 13 '21 at 20:31
  • Computed property has data after its fetched. The issue is, if there's no data, it gives that error. So, I solved it by adding a random DIV if the array is empty, but I feel like there should be a different approach to that. Seems hacky. (btw Vue is throwing an error - computed property is equal to the correct data after a few seconds (but after mounted)). – Torewin Mar 13 '21 at 20:35
  • There is another approach. Fix your `computed` to work correctly is there is no data. That's it – Michal Levý Mar 13 '21 at 20:43
  • What should it do? it already returns an empty array initially? I think the issue is `grid-view` does not have any content in it with the slot? – Torewin Mar 13 '21 at 20:48