manuel.menendez
manuel.menendez

Reputation: 305

Vue.js - how to fill an array while using v-for

I'm working in a routes project in Vue2. I won't explain the details to make this question as simple as possible.

I'm using a v-for to iterate through an array.

Each iterated object needs to be added to an array which I'm going to send to another component in my template.

It's a complex JSON. I'm on a leaflet map.

I need to join each point's coordinate with a polyline. The <l-polyline> component is expecting an array of coordinates (each coordinate is an array of 2 values).

So, my take is to put each object.coordinate into an array as I iterate over the first list. Then that array is going to be passed as a parameter to the polyline component in the template. How do I do that?

<div :key="i" v-for="(route, i) in jsonResult.routesList">
    <div :key="j" v-for="(stop, j) in route.stopsList">
        <l-marker :lat-lng="latLng(stop.lat, stop.long)" />
        // the problem is here because I'm only getting one object (stop) and I need the whole list of stops to get their coordinates
        <l-polyline :lat-lngs="latLng(stop.lat, stop.long)"></l-polyline>
    </div>
</div>

My JSON looks more or less like this:

The <l-polyline> object expects an array like this to draw the lines:

    [
      [20.567934, -103.366844],
      [19.54006, -99.1879349],
      [25.54193, -100.947906],
      [25.7970467, -100.59623]
    ] 

The routes list (jsonResult.routesList in the code)

"routesList": [
    {
      "stopsList": [
        {
          "id": 1,
          "seq": 1,
          "start": "2019-09-10T09:32:23",
          "end": "2019-09-10T10:17:23",
          "lat": 20.567934,
          "long": -103.366844,
        },
        {
          "id": 2,
          "seq": 2,
          "start": "2019-09-10T09:32:23",
          "end": "2019-09-10T10:17:23",
          "lat": 20.587934,
          "long": -104.386844,
        }
      ],

    },
    //another route
    {
      "stopsList": [
        {
          "id": 1,
          "seq": 1,
          "start": "2019-09-10T09:32:23",
          "end": "2019-09-10T10:17:23",
          "lat": 20.567934,
          "long": -103.366844,
        },
        {
          "id": 2,
          "seq": 2,
          "start": "2019-09-10T09:32:23",
          "end": "2019-09-10T10:17:23",
          "lat": 20.587934,
          "long": -104.386844,
        }
      ],
    },

Upvotes: 1

Views: 1627

Answers (2)

Dawid Zbiński
Dawid Zbiński

Reputation: 5826

You should use a method in order to compute the array of coordinates you want to pass to the other component.

// Vue component file
methods: {

  /*
   * Converts the stopsList array to an array of coordinates.
   * Example of returned value:
   *   [
   *     [ 23.1234, 21.2322 ],
   *     [ 21.1242, 24.2333 ],
   *   ]
   */
  getStopsCoordinates(stops) {
    return stops.map(stop => [ stop.lat, stop.long ]);
  }
}

You can then use the getStopsCoordinates method when you're passing the stops coordinates of all stops, like so:

<div :key="i" v-for="(route, i) in jsonResult.routesList">
    <div :key="j" v-for="(stop, j) in route.stopsList">
        <l-marker :lat-lng="latLng(stop.lat, stop.long)" />
        // the problem is here because I'm only getting one object (stop) and I need the whole list of stops to get their coordinates
        <l-polyline :lat-lngs="getStopsCoordinates(route.stopsList)"></l-polyline>
    </div>
</div>

Although it should work, it's not an optimal solution, as the list is converted each time in the second v-for and it's probably not needed. There's multiple ways on how this can be optimised, but without the measurements etc. I'd probably go with a getter for routesList.

// Vue component file
getters: {

  /* Returns routesList where each route has property stopsCoordinates */
  routesListWithStopsCoordinates() {
    return this.jsonResult.routesList.map(route => {
      route.stopsCoordinates = this.getStopsCoordinates(route.stopsList);
      return route;
    })
  }
},

methods: {

  /* Already explained above */
  getStopsCoordinates(stops) {
    return stops.map(stop => [ stop.lat, stop.long ]);
  }
}

Then in your template you can do something like this:

<div :key="i" v-for="(route, i) in jsonResult.routesList">
    <div :key="j" v-for="(stop, j) in route.stopsList">
        <l-marker :lat-lng="latLng(stop.lat, stop.long)" />
        // the problem is here because I'm only getting one object (stop) and I need the whole list of stops to get their coordinates
        <l-polyline :lat-lngs="route.stopsCoordinates"></l-polyline>
    </div>
</div>

Hope it works.

Upvotes: 2

Lawrence Gil
Lawrence Gil

Reputation: 415

I think the problem is in the way that your using your <div>, when you say:

<div :key="j" v-for="(stop, j) in route.stopsList">
        <l-marker :lat-lng="latLng(stop.lat, stop.long)" />
        // the problem is here because I'm only getting one object (stop) and I need the whole list of stops to get their coordinates
        <l-polyline :lat-lngs="latLng(stop.lat, stop.long)"></l-polyline>
</div>

In the v-for you were passing each individual element from the stopList to the <l-polyline> component. I think the correct approach would be to pass the whole stopList to the component, and then format it accordingly (iterating over the stopList array is done inside the <l-polylist> component.

<div :key="i" v-for="(route, i) in jsonResult.routesList">
      <div :key="j" v-for="(stop, j) in route.stopsList">
        <l-marker :lat-lng="latLng(stop.lat, stop.long)" />


      <l-polyline :lat-lngs="route.stopsList.map(x=>[x.lat,x.long])"></l-polyline>
</div>
</div>

Of course this is not an optimal approach, but it will solve your problem, a better way would be using something based on the idea of Dawid Zbiński and use a computed property. I hope this helps

Upvotes: 3

Related Questions