madsongr
madsongr

Reputation: 785

V-for from a nested array

I'm starting with vue.js and I need to populate selects with v-for that are inside another v-for.

I was reading questions about this subject but could not find a way to make it works in my case.

I have a nested array (tours) with title and description and I have a v-for inside another one to populate a select with tours' title:

enter image description here

html:

<div class="row" id="app">
    <div v-for="(item, index) in hosters" v-bind:key="item.id" class="col-md-6 mb-50">
        <h4 class="mb-0">{{ item.name }} {{ item.lastname }}</h4>


        <div class="tour-options-select">
            <select id="select-suggestions" name="tour-options-dropdown" class="tour-options-dropdown">
                <option v-for="tour in tours">{{ tour.title }}</option>
            </select>
        </div>
    </div>
</div>

vue.js:

let app = new Vue({

    el: '#app',
    data: {
        city: 'mycity',
        hosters: null,
        tours: [],
        title: [],
    },

    created: function () {
        this.searchHoster()
    },
    methods: {
        searchHoster: function () {
            axios.post('searchHoster.php', { "city": this.city }).then((response) => {

            this.hosters = response.data.hosters;
            console.log(this.hosters);

            this.tours = this.hosters.map(res => res.tours);
            console.log(this.tours);

            this.title = this.tours.map(res => res.title);
            console.log(this.title);

            }).catch((error) => {

                console.log(error);

            });

        },

    }
})

I’m getting undefined in console.log(this.title); line so i tried to use:

this.title = response.data.hosters.map(hoster => hoster.tours).flat().map(item => item.title);

but it gives me a simple array with all the titles of all users. So, all selects are populated with the same titles for everyone. Any tip about how to make it works?

Upvotes: 1

Views: 1764

Answers (3)

Dipyamanbiswas
Dipyamanbiswas

Reputation: 71

<div class="tour-options-select">
            <select id="select-suggestions" name="tour-options-dropdown" class="tour-options-dropdown">
                <option v-for="tour in  ̶t̶o̶u̶r̶  item.tours">{{ tour.title }}</option>
            </select>
        </div>

Change the tours to item.tours

Since you are already iterating through the first v-for the context for the 2nd v-for is "item". and item.tours would give you the proper object to iterate over.

Upvotes: 1

Rodney P. Barbati
Rodney P. Barbati

Reputation: 2100

Do not break out the various pieces of data you are interested in rendering. Instead, render the inner portions using the index value from the outer v-for. For example, assuming your data looks like the data you depicted, then...

V-for="item in data"
    Render host info using item.name, etc.
    v-for="tour in item.tours"
        Render title and description from tour.title, etc.

Much faster and easier. I might also suggest using an accordion type control as well - render a table of all the tours, and allow user to select the desired row by check box (which would then display further details in a details area). - that way they can see all the options easily. Make the items collapsible using @click to toggle a boolean value which controls show=boolean on a nested div.

Good luck.

Upvotes: 1

Hans Felix Ramos
Hans Felix Ramos

Reputation: 4434

Change tours to item.tours on second v-for:

<div v-for="(item, index) in hosters" v-bind:key="item.id" class="col-md-6 mb-50">
    <h4 class="mb-0">{{ item.name }} {{ item.lastname }}</h4>

    <div class="tour-options-select">
        <select id="select-suggestions" name="tour-options-dropdown" class="tour-options-dropdown">
            <option v-for="tour in item.tours">{{ tour.title }}</option>
        </select>
    </div>
</div>

Upvotes: 1

Related Questions