1

I am trying to figure out something and having issues with it. I have some icons data that I am receiving from an array inside an array and I want to put an event handler on only one of the icons. For example, let's say put an event handler on thumbs up icon to hide a paragraph (something like that).

I have made a codepen for demonstration: https://codepen.io/anon/pen/gNxdER

<div id="app">
  <v-app id="inspire">
    <v-container>
      <v-data-table
        v-model="selected"
        :headers="headers"
        :items="desserts"
        item-key="name"
      >
        <template v-slot:items="props">
          <td>{{ props.item.name }}</td>
          <td>{{ props.item.calories }}</td>
          <td>{{ props.item.iron }}</td>
          <td><v-icon v-for="icon in props.item.icons">{{icon}}</v-icon></td>
        </template>
      </v-data-table>
    </v-container>
  </v-app>
</div>
new Vue({
  el: '#app',
  data () {
    return {
      headers: [
        {
          text: 'Dessert (100g serving)',
          align: 'left',
          sortable: false,
          value: 'name'
        },
        { text: 'Calories', value: 'calories' },
        { text: 'Iron (%)', value: 'iron' },
        { text: 'Icons', value: 'icon'}
      ],
      desserts: [
        {
          name: 'Frozen Yogurt',
          calories: 159,
          iron: '1%',
          icons: [
            'search',
            'dashboard',
            'timeline',
            'thumb_up'
          ]
        },
        {
          name: 'Ice cream sandwich',
          calories: 237,
          iron: '1%',
          icons: [
            'search',
            'dashboard',
            'timeline',
            'thumb_up'
          ]
        },
        {
          name: 'Eclair',
          calories: 262,
          iron: '7%',
          icons: [
            'search',
            'dashboard',
            'timeline',
            'thumb_up'
          ]
        },
        {
          name: 'Cupcake',
          calories: 305,
          iron: '8%',
          icons: [
            'search',
            'dashboard',
            'timeline',
            'thumb_up'
          ]
        }
      ]
    }
  }
})

Thank you for the help.

2 Answers 2

2

You could do something like this using v-on:

<v-icon v-for="icon in props.item.icons" v-on="getIconHandlers(icon)">{{icon}}</v-icon>

with:

getIconHandlers (icon) {
  if (icon === 'thumb_up') {
    return {click: this.thumbUpClickHandler}
  }
      
  return null
}

You will, of course, also have to define the function thumbUpClickHandler. More likely you'll want to pass some context for the current row to the click handler, which can be achieved by passing that extra information to getIconHandlers and capturing it in the closure of the listener:

getIconHandlers (icon, otherStuff /* <- pass whatever you need */) {
  if (icon === 'thumb_up') {
    return {
      click: () => {
        this.thumbUpClickHandler(otherStuff)
      }
    }
  }
      
  return null
}

It is possible to do all of this inline in the template instead but I think it's easier to understand pulling it out to a separate method.

This is taking advantage of the object syntax supported by v-on, very similar to v-bind. It's documented at https://v2.vuejs.org/v2/api/#v-on. The properties of that object are registered as listeners using the property keys as the event names and the property values as the corresponding listener functions. For the other icons I just return null though you could also return an empty object.

Vuetify will show a different mouse cursor for icons that have click listeners and doing it this way will only change the cursor for the thumb_up icon, which I assume is the intent here.

Update:

As only one event is required it is also possible to do this using the square bracket expression syntax for v-on/@. e.g.

@[getEventName(icon)]="onThumbIconClick"

Here getEventName would be a method such as:

getEventName (icon) {
  return icon === 'thumb_up' ? 'click' : null
}

There's special handling inside v-on that ensures no listener is registered when the expression evaluates to null.

Personally I prefer the object syntax I described previously but for the sake of completeness I thought it worth a mention.

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

Comments

2

After v-for attach a click event which will call a method, which you pass the item to.

<v-icon v-for="icon in props.item.icons" @click="iconAction(item, icon)">{{icon}}</v-icon>

In your method, you then can do something on the item based upon which item was clicked.

methods: {
  iconAction (item, icon){
    if (icon === 'thumbs_up') {
      // do somthing for thumbs_up
    } else if (icon === 'dashboard') {
      // do somthing for dashboard
    }
    ...
  }
}

1 Comment

short and sweet . Thank you

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.