Lakshay Khandelwal
Lakshay Khandelwal

Reputation: 81

How to get the index value of v-for as a argument of a function of computed property in Vue?

I want to take the index value of v-for (which is in path tag) as a parameter in a function stateData(index) defined in computed property in Vue. I have tried to do this by v-model="stateData[index]" but the console box is showing an error that path tag is not supporting v-model(you can see by running the snippet).

Does anyone have any idea?

  var app = new Vue({
      el: "#app",
      data(){
        return {
                statesJson: null,
                }
            },
        methods:{
          axiosCall() {
               axios.all([axios.get('https://raw.githubusercontent.com/smlab-niser/CRiAPGraph/master/India.json')])
              .then(axios.spread((user1) => (
               this.statesJson=user1.data
      )))
              .catch(error => {
               console.log(error)
      })
    },    
        },
        computed: {
        // Typical projection for showing all states scaled and positioned appropriately
        projection () {
          return d3.geoMercator().scale(900).translate([-1030, 700])
        },

        // Function for converting GPS coordinates into path coordinates
        pathGenerator () {
          return d3.geoPath().projection(this.projection)
        },
            // Combine the states GeoJSON with a rank-based gradient
        stateData (index) {
          return this.statesJson ? this.statesJson.features.map(feature => {
            return {
              feature
            }
          }):[]
        }
       },
      created:function(index){
            this.axiosCall();
          },
     })
   <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.2/axios.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
    <div id="app">
            <div>
                <svg id="svg" ref="svg" height="600" width="510">
                    <path class="bar" v-for="(state, index) in stateData" v-model="stateData[index]"  :d="pathGenerator(state.feature)" :style="{
           stroke: 'darkslategray'
         }">
                    </path>
                </svg>
            </div>
         </div>

Upvotes: 0

Views: 665

Answers (1)

Maarten Veerman
Maarten Veerman

Reputation: 1621

See below an example on how to use objects in for loops. I've simplified your code, I don't think there is any need to use the index, as you can see below.

I've removed the statesData function, since it basically maps an array to an array, so you can simplify that by accessing the statesJson.features object immediately on the v-for.

I than use the state from the v-for as input in a new calcFill function. Inside that function, which is in the methods propery of your Vue component, you can calculate the gradient by rank. Using the state object, we can now simply access state.rank immediately, no need for using the index.

This is just an example showing that sometimes it's better to keep objects as they are and work with those object directly as method parameters.

When you run the snippet, you see each state is now color coded by it's rank.

var app = new Vue({
      el: "#app",
      data(){
        return {
                statesJson: null,
                }
            },
        methods:{
          axiosCall() {
               axios.all([axios.get('https://raw.githubusercontent.com/smlab-niser/CRiAPGraph/master/India.json')])
              .then(axios.spread((user1) => (
                this.statesJson=user1.data
               )))
              .catch(error => {
               console.log(error)
              })
          },
          calcFill(state) { // Here you can do your rank based gradient
            let l = this.statesJson.features.length
            let rank = state.rank
            let num = (rank / l) * 255 // Calculate color code
            return 'rgb(' + num + ', ' + num + ', ' + num + ')'
          }
        },
        computed: {
          // Typical projection for showing all states scaled and positioned appropriately
          projection () {
            return d3.geoMercator().scale(900).translate([-1030, 700])
          },

          // Function for converting GPS coordinates into path coordinates
          pathGenerator () {
            return d3.geoPath().projection(this.projection)
          }
       },
      created:function(index){
            this.axiosCall();
          },
     })
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.2/axios.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
    <div id="app">
            <!-- Only show if statesJson is loaded -->
            <div v-if="statesJson">
                <svg id="svg" ref="svg" height="600" width="510">
                    <!-- Loop directly on statesJson, keeping the object -->
                    <path class="bar" v-for="(state, index) in statesJson.features"  :d="pathGenerator(state)" :style="{
           stroke: 'darkslategray', fill: calcFill(state)
         }">
                    </path>
                </svg>
            </div>
         </div>

Upvotes: 1

Related Questions