Search code examples
vuejs2v-for

Setting tabIndex nicely in VueJS when iterating over multiple objects


I have a couple of nested objects I need to iterate over to create inputs. I've dumbed it down to an example below. I would like to set tabIndexes in these inputs.

<div v-for="(iv, ik, ii) in {a: 'x', b: 'x'}" :key="ii">
  <div v-for="(jv, jk, ji) in {a: 'y', b: 'y'}" :key="ji">
    <div v-for="(kv, kk, ki) in {a: 'z', b: 'z', c: 'z'}" :key="ki">
      <input type="text" :tabindex="(ii * 100) + (ji * 10) + ki" />
      <label>{{(ii * 100) + (ji * 10) + ki}}</label>
    </div>
  </div>
</div>

What is the best way to be able to set my tabindex to 0, 1, 2, 3, etc? I found that setting a third arg on the v-for provides a numeric index, but what I've got seems a little convoluted. Is there a better way I can go about this?

The above results in output like the following:

[___________] 0
[___________] 1
[___________] 2
[___________] 10
[___________] 11
[___________] 12
[___________] 100
[___________] 101
[___________] 102
[___________] 110
[___________] 111
[___________] 112

Which works, but seems less than ideal. I know the tab key will work as intended if they're sequential and that gaps seem fine. But is there a cleaner way I could get 1 through 12 instead of the staggered numbers I've got? Basically like a running index (x++, etc) for each time I hit the ?

I tried setting an int in the 'data' and then a method to increment that, but quickly threw myself into an infinite re-rendering loop.

Thanks.


Solution

  • there is a trick to doing this, but it's a hack, and not exactly a best practice

    Template:

    {{numitems = 0 | hide}}
    <div v-for="(iv, ik, ii) in {a: 'x', b: 'x'}" :key="ii">
      <div v-for="(jv, jk, ji) in {a: 'y', b: 'y'}" :key="ji">
        <div v-for="(kv, kk, ki) in {a: 'z', b: 'z', c: 'z'}" :key="ki">
          <input type="text" :tabindex="numitems += 1" />
          <label>{{(ii * 100) + (ji * 10) + ki}}</label>
        </div>
      </div>
    </div>
    

    script hide Filter definition

    filters: {
      hide: function(value){
        return ''
      }
    }
    

    you don't need the hide filter, but it ensures that you don't put anything into the template during definition. You can also define numitems in data. And use methods to reset and increment.


    another option is setting up a computed value that uses the number you generate as an index to the incremental values without any gaps.

    Whenever your objects' keys change, you can do the calculation, generating the keys either using your method, or using an object.

    here's an example that uses ${ik}_${jk}_${kk} as the key

    tabIndexVals(): {
      let c = 0;
      let o = {};
      Object.keys(i).forEach(ik => {
        Object.keys(i[ik]).forEach(jk => {
          Object.keys(i[ik][jk]).forEach(kk => {
            let key = `${ik}_${jk}_${kk}`;
            o[key] = c;
            c++;
          })
        })
      })
      return o;
    }