Adrian Baran
Adrian Baran

Reputation: 895

Computed properties in nested loop

I wonder if I can access computed property in nested loop based on current item. As for now I achieved it by creating a method to get a specific property. Is there a way to do it without this extra method?

EDIT I update my example to make it more clear.

const vm = new Vue({
  el: '#app',
  data: {
    categories: [
      { id: 0, text: 'zero' },
      { id: 1, text: 'one' },
      { id: 2, text: 'two' },
    ],
    minions: [
      { name: 'A', category: 'zero' },
      { name: 'B', category: 'zero' },
      { name: 'C', category: 'one' },
      { name: 'D', category: 'two' },
    ],
  },
  methods: {
    getComputedData: function (name) {
      return this[name];
    },
  },
  computed: {
    zero: function () {
      return this.minions.filter(({category}) => category === 'zero');
    },
    one: function () {
      return this.minions.filter(({category}) => category === 'one');
    },
    two: function () {
      return this.minions.filter(({category}) => category === 'two');
    }
  },
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.4/vue.min.js"></script>

<div id="app">
  <div
    v-for="category in categories"
  >
    <h1>{{ category.text }}</h1>
    <ul>
      <li
        v-for="minion in getComputedData(category.text)"
      >{{ minion.name }}</li>
    </ul>
  </div>
</div>

Upvotes: 1

Views: 2268

Answers (1)

Roy J
Roy J

Reputation: 43881

You can refer to the viewmodel as $root, so the computeds you have named for your categories are $root[category.text]. See the snippet below.

If you were in a component, you wouldn't have the special $root variable, and would have to resort to eval(category.text).

In either case, there is a code smell here, as you're making named objects based on data (and your computeds are mostly repeated code). You would do better to create a single computed or function that covers all the categories.

const vm = new Vue({
  el: '#app',
  data: {
    categories: [
      { id: 0, text: 'zero' },
      { id: 1, text: 'one' },
      { id: 2, text: 'two' },
    ],
    minions: [
      { name: 'A', category: 'zero' },
      { name: 'B', category: 'zero' },
      { name: 'C', category: 'one' },
      { name: 'D', category: 'two' },
    ],
  },
  computed: {
    zero: function () {
      return this.minions.filter(({category}) => category === 'zero');
    },
    one: function () {
      return this.minions.filter(({category}) => category === 'one');
    },
    two: function () {
      return this.minions.filter(({category}) => category === 'two');
    }
  },
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.4/vue.min.js"></script>

<div id="app">
  <div
    v-for="category in categories"
  >
    <h1>{{ category.text }}</h1>
    <ul>
      <li
        v-for="minion in $root[category.text]"
      >{{ minion.name }}</li>
    </ul>
  </div>
</div>

Upvotes: 1

Related Questions