Search code examples
vue.jsvuexgettervue-props

How can I "dynamically" pass a veux getter as a prop to my child component?


I am trying to dynamically pass an array into my component's prop. The issue is that this array is fetched by a getter. The reason is that I have multiple lists being fetched from the store and would like to pass them down using a loop.

Parent.vue (see line: 2)

<v-tab-item v-for="item in tabItems" :key="item.list">
  <searchCard :items="item.list">
    <template v-slot:content="prop">
      <v-card-title class="text-capitalize">{{ prop.item.name }}</v-card-title>
      <v-card-text>
        <p>Rate:&nbsp;{{ prop.item.rate }}/{{ prop.item.unit }}</p>
        <p>Quantity:&nbsp;{{ prop.item.quantity }}</p>
      </v-card-text>
      <v-card-actions>
        <v-spacer></v-spacer>
        <plusMinusGroup>
          <p slot="value">{{ prop.item.quantity || 0 }}</p>
        </plusMinusGroup>
      </v-card-actions>
    </template>
  </searchCard>
</v-tab-item>

This is what my tabItems array looks like and the mapped getters

tabItems: [
  { list: 'prodList', cardHeight: 20 },
  { list: 'materialList', cardHeight: 20 },
  { list: 'itemList', cardHeight: 20 },
],

...mapGetters({
  prodList: 'products/productList',
  materialList: 'materials/materialList',
  itemList: 'items/itemList',
}),

The issue is that the value is being intercepted as a String literal (which makes sense) and I can't get it to work.

I have tried substituting { list: "prodList", cardHeight: 20 }, with { list: this.prodList, cardHeight: 20 }, but that doesn't help.

Also, because my Vuex is split into various modules, I cant use the string provided to fetch the getter inside the child module.


Solution

  • The main difficulty here is that there isn't a $computed equivalent to $data. If there were this would be easy.

    One option is to put an explicit this in the template:

    <searchCard :items="this[item.list]">
    

    If you're running a linter it'll probably complain about that though.

    The instance does have a reference to itself in the _self property. The underscore indicates that it's private so we shouldn't really be using it. In theory you could create your own alias:

    data () {
      return {
        self: this
      }
    }
    

    then:

    <searchCard :items="self[item.list]">
    

    Seems a bit hacky though.

    There are tricks using property getters that would work but I think that would just complicate things. e.g. Putting a getter on each tab item that proxies through to the relevant list.

    The simplest way would probably be to provide a method:

    methods: {
      getList (listName) {
        return this[listName]
      }
    }
    

    with:

    <searchCard :items="getList(item.list)">
    

    To me that seems the least likely to cause confusion to future maintainers of the code.