Dan Knights
Dan Knights

Reputation: 8368

Data not being passed to Vue component

I have a Vue component receiving an array of 'items' from its parent.

I've sorted them into categories, two 'items' in each category:

computed: {
        // sort items into categories
        glass: function() {
            return this.items.filter(i => i.category === "glass").slice(0, 2);
        },
        ceramics:
        // etc...

I need to place both items in categories.items to then pass them as props to another component:

data() {
        return {
            categories: [
                { name: "Glass", sort: "glass", items: {} },
                { name: "Ceramics", sort: "ceramics", items: {} },
                { name: "Brass", sort: "brass", items: {} },
                { name: "Books/Comics", sort: "books", items: {} },
                { name: "Collectibles", sort: "collectibles", items: {} },
                { name: "Pictures", sort: "pictures", items: {} },
                { name: "Other", sort: "other", items: {} }
            ]
        };
    },

When I use created or mounted nothing is passed through, when I use beforeDestroy or destroy and console.log the results it works fine, but, they're of no use when exiting the page.

The 'items' are from an Axios GET request, could this be why?

GET request from parent component:

methods: {
        fetchItems() {
            // items request
            let uri = "http://localhost:8000/api/items";
            this.axios.get(uri).then(response => {
                // randomize response
                for (let i = response.data.length - 1; i > 0; i--) {
                    const j = Math.floor(Math.random() * (i + 1));
                    [response.data[i], response.data[j]] = [
                        response.data[j],
                        response.data[i]
                    ];
                }

                this.items = response.data;
            });
        }
    },

Passing props to child component:

        <div
            class="items-container"
            v-for="category in categories"
            :key="category.name"
        >
            <router-link :to="'category.link'" class="category-names-home-link">
                <h2 class="category-names-home">{{ category.name }}</h2>
            </router-link>
            <router-link
                :to="'category.link'"
                class="home-view-all"
                @mouseover.native="expand"
                @mouseout.native="revert"
                >View All...</router-link
            >
            <div class="items">
                <!-- Pass to child component as props: -->
                <SubItem :item="categories.items" />
                <SubItem :item="categories.items" />
            </div>
        </div>

Upvotes: 1

Views: 491

Answers (1)

Dan
Dan

Reputation: 63059

  • Don't bother adding the items to the categories, keep them separate
  • Instead of multiple computeds, use one computed object hash to store all the filtered sets:
computed: {
  filtered() {
    if (!this.items) return null;
    const filtered = {};
    this.items.forEach(item => {
      if (filtered[item.category]) {
        filtered[item.category].push(item);
      } else {
        filtered[item.category] = [item];
      }
    });
    return filtered;
  }
}

Result:

{
'Glass': [ ... ],
'Ceramic': [ ... ]
...
}

In the template:

<div>
   <div v-for="category in categories" :key="category.name">
      <div class="items" v-for="item in filtered[category.name]">
         <SubItem :item="item" />
      </div>
   </div>
</div>

You can use a v-if in the parent to prevent displaying anything until the data is loaded:

<display v-if="items" :items="items"></display>

Here is a demo

Upvotes: 1

Related Questions