Search code examples
arraysjsonvue.jsv-for

Unable to show all objects in array on v-for loop, only showing last object


I'm pulling in some data. I'm grouping this data by key and then trying to print that out in a v-for loop in Vue.

The code looks something like this:

// I initialize an empty array in data
data() {
  return {
    locArray: []
  }
}


// This is done in the api call, in beforeRouteEnter()

const items = data.continental;

Array.prototype.groupBy = function(prop) {
  return this.reduce(function(groups, item) {
    const val = item[prop];
    groups[val] = groups[val] || [];
    groups[val].push(item);
    return groups;
  }, {});
};

for (let i in items) {
  let source = items[i];
  let details = source.details;
  let groupedByLocation = details.groupBy(location);
  vm.locArray = groupedByLocation
}

// This is an example of what the data looks like
{
  data: {
    continental: {
      countryOne: {
        weather: "weatherOne",
        details: [{
          location: "west",
          foods: "foodOne",
          mainCities: [
            "cityOne",
            "cityTwo",
            "cityThree"
          ]
        }]
      },
      countryTwo: {
        weather: "weatherTwo",
        details: [{
          location: "north",
          foods: "foodTwo",
          mainCities: [
            "cityOne",
            "cityTwo",
            "cityThree"
          ]
        }]
      },
      countryThree: {
        weather: "weatherThree",
        details: [{
          location: "north",
          foods: "foodThree",
          mainCities: [
            "cityOne",
            "cityTwo",
            "cityThree"
          ]
        }]
      },
      countryFour: {
        weather: "WeatherFour",
        details: [{
          location: "west",
          foods: "foodFour",
          mainCities: [
            "cityOne",
            "cityTwo",
            "cityThree"
          ]
        }]
      },
      countryfive: {
        weather: "WeatherFive",
        details: [{
          location: "north",
          foods: "foodFive",
          mainCities: [
            "cityOne",
            "cityTwo",
            "cityThree"
          ]
        }]
      }
    }
  }
}
<div class="entry-content">
  <div class="single-entry" v-for="loc in locArray" :key="loc.id">
    <span class="test-wrap">{{ loc }}</span>
  </div>
</div>

When I console.log(groupedByLocation) I get all the data that's supposed to show up, but in v-for I'm only getting the last object in the array.

It seems simple but I'm really stumped.

Any help will be greatly appreciated!

The desired outcome is that I'd like to print all the items that have location: north together in a group above and all the items that have location: west in a different group below.


Solution

  • I don't understand why you're calling groupBy on each iteration of your for loop.

    I would solve this filtering by details[0].location the Object.values()s of continental:

      methods: {
        filterByLocation: function(location) {
          return Object.values(this.continental).filter(v => v.details[0].location === location)
        }
      }
    

    Example:

    new Vue({
      el: '#app',
      data: {
        continental: {
          countryOne: {
            weather: "weatherOne",
            details: [{
              location: "west",
              foods: "foodOne",
              mainCities: [
                "cityOne",
                "cityTwo",
                "cityThree"
              ]
            }]
          },
          countryTwo: {
            weather: "weatherTwo",
            details: [{
              location: "north",
              foods: "foodTwo",
              mainCities: [
                "cityOne",
                "cityTwo",
                "cityThree"
              ]
            }]
          },
          countryThree: {
            weather: "weatherThree",
            details: [{
              location: "north",
              foods: "foodThree",
              mainCities: [
                "cityOne",
                "cityTwo",
                "cityThree"
              ]
            }]
          },
          countryFour: {
            weather: "WeatherFour",
            details: [{
              location: "west",
              foods: "foodFour",
              mainCities: [
                "cityOne",
                "cityTwo",
                "cityThree"
              ]
            }]
          },
          countryfive: {
            weather: "WeatherFive",
            details: [{
              location: "north",
              foods: "foodFive",
              mainCities: [
                "cityOne",
                "cityTwo",
                "cityThree"
              ]
            }]
          }
        }
      },
      methods: {
        filterByLocation: function(location) {
          return Object.values(this.continental).filter(v => v.details[0].location === location)
        }
      }
    })
    #app {
      display: flex;
      justify-content: space-around;
      max-width: 600px;
      margin: 0 auto;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
    <div id="app">
      <div>
        <h2>North locations</h2>
        <ol>
          <li v-for="loc in filterByLocation('north')" :key="loc.weather">
            {{loc.weather}}
          </li>
        </ol>
      </div>
      <div>
        <h2>West locations</h2>
        <ol>
          <li v-for="loc in filterByLocation('west')" :key="loc.weather">
            {{loc.weather}}
          </li>
        </ol>
      </div>
    </div>