0

I got 2 array, one for states and another one for countries. I want to display the country name of the state. So, I'm using Laravel 5.7 for the backend and I get data using this for the countries Country::get(); and Vue.js recieve the array like this:

countries:Array(4)
    0:created_at:(...)
        deleted_at:(...)
        id:(...)
        name:(...)
        shortName:(...)
        updated_at:(...)
    1:{…}
    2:{…}
    3:{…}

I do the same for the state as the country. State::get(); and vue recieve this:

states:Array(1)
    0:country_id:(...)
        created_at:(...)
        deleted_at:(...)
        id:(...)
        name:(...)
        shortName:(...)
        updated_at:(...)

When I display the data into the table using v-for:

<tbody>
    <tr v-for="state in data.states">
        <td>{{SOMTHING TO DISPLAY COUNTRY NAME}}</td>
        <td>{{state.name}}</td>
        <td></td>
    </tr>
</tbody>

At the first cell, I tried to do {{data.countries[state.country_id]['name']}} but it failed. Instead it display another country in the array where the key correspond to the country_id I gave.

I know that I can solve my problem by doing this State::with('country')->get(); and then into my vue component doing this state.country.name, but since I already send every country, I'm looking for another way to perform it.

Any idea?

2 Answers 2

1

You want to JOINyour country data to your state data using state.country_id mapped to country.id.

Map your countries by ID

const cmap = {} // in your vue.data
countries.forEach(it=>cmap[it.id] = it)

Or use reduce

const cmap = countries.reduce((acc,cur)=>{acc[cur.id]=cur; return acc},{})

Put the map in a computed property so it is calculated one time on demand.

countryMap(){
    return this.countries.reduce((acc,cur)=>{acc[cur.id]=cur; return acc},{})
}

Create a lookup method

getCountryName(state){
    return this.countryMap[state.country_id].name
}

Use it in a template like this

<div>{{getCountryName(state)}}</div>

You don't need a lookup method, but if you are using Vue, it makes sense to break things up. this.countryMap[state.country_id].name is a bit messy in a template.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you, this work like a charm. I did some change to adapt to vue.js. I used your reduce function as a computed property countriesMap: function() { return this.data.countries.reduce((acc,cur)=>{acc[cur.id]=cur; return acc},{}); } then I just have to use the computed property like you did in the lookup {{countriesMap[state.country_id].name}}. When I create a country, it add it to the map and if I create a state without reloading, it display the country name as well! Big thank you!!!
@ElieMorin using map as computed is a GREAT idea. You got it!
0

Since I'm using map with many object, I just changed my code in a way that I don't need to repeat myself everytime.

Since now, the code is a method instead of a computed property.

dataMap: function($model) {
    return this.data[$model].reduce((acc,cur)=>{acc[cur.id]=cur; return acc},{});
},

I use it this way into the component:

{{dataMap('countries')[dealer.country_id].name}}

And my data look like this:

export default {
    data() {
        return {
            data: {
                countries:{...},
                states:{...},
                cities:{...},
                groups:{...},
                dealers:{...},
                users:{...},
            },
        }
    },

So that way I can use the dataMap method for anything found into data array without having to recode a new map computed property. I just have to do this:

{{dataMap('users')[something.user_id].field}}
{{dataMap('groups')[something.group_id].field}}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.