0

I have a data table containing clickable rows. All is working well, I encountered one problem. If I want to highlight text on the row, the click event is triggered. The only thing I found that could help is the .exact modifier. Hoping it will ignore the click handler if text is highlighted. But the click event is still triggered.

My Question: Is there a way I can highlight text on an item without triggering the click event.

Expected Result: Using @click.exact wont fire click event when highlighting text

Actual Result: Click event is fired when highlighting text, event using @click.exact

Side Note: It manages to hightlight the text, but as soon as you let the mouse button go, it triggers the click event.

<v-data-table
    v-show="model.id && !editMode"
    :headers="bagHeaders"
    :items="bags"
    class="elevation-1"
    item-key="id"
    :loading="bagsStatus.loading"
    :pagination.sync="pagination"
    >
        <template slot="items" slot-scope="props">
            <tr @click.exact="onBagClick(props.item.id)">
                <td class="text-xs-left" v-for="header in bagHeaders" :key="header.id">{{ formatColumn(header, props.item) }}</td>
            </tr>
        </template>
</v-data-table>

Edit: Other Attempts: @click.prevent also not working

Best work around so far: https://codepen.io/anon/pen/YBNLLy

4
  • What about @click.prevent? Commented Jan 31, 2019 at 11:43
  • @jom also not working. Commented Jan 31, 2019 at 11:45
  • What does this onBagClick() method do? Commented Jan 31, 2019 at 11:47
  • @jom It just navigate to other component. But its trivial what it does. It should not be called at all. Commented Jan 31, 2019 at 11:50

1 Answer 1

1

OK, try @click.stop on the TDs which stops the event from propagating to the parent TR.

Since you want to preserve the normal row clicking behavior on certain condition, you could add a method for inspecting if any text-selection is being made while clicking and proceed with stopping the event propagation, otherwise invoke the onBagClick() method of the parent TR:

new Vue({
  el: '#app',

  methods: {
    onBagClick(id) {
      alert('Bag Click');
    },

    checkMouseAction(e) {
      const isTextHighlighting = window.getSelection().toString().trim() !== '';

      if (!isTextHighlighting) {
        e.target.parentElement.click();

        // Or call the this.onBagClick() instead
      }
    }
  }
})
table {
  border-collapse: collapse;
}

table td {
  border: 1px solid;
  padding: 10px;
}

table td:first-child {
  background-color: lavender;
}

table td:last-child {
  background-color: pink;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
  <table>
    <tr @click="onBagClick">
      <td @click.stop="checkMouseAction">Selectable text. Left-click and drag these lines with your mouse.</td>
      <td>Hardly selectable text. An alert dialog will get in the way by popping up.</td>
    </tr>
  </table>
</div>


Edits

The above will work too, but actually I figured out another obvious workaround: Do the text-selection checking on the table row level:

Working demo

new Vue({
  el: '#app',
  data() {
    return {
      headers: [
        {
          text: 'Dessert (100g serving)',
          align: 'left',
          sortable: false,
          value: 'name'
        }, 
        {
          text: 'Calories',
          value: 'calories'
        }, 
        {
          text: 'Fat (g)',
          value: 'fat'
        }, 
        {
          text: 'Carbs (g)',
          value: 'carbs'
        }, 
        {
          text: 'Protein (g)',
          value: 'protein'
        }, 
        {
          text: 'Iron (%)',
          value: 'iron'
        }
      ],
      desserts: [
        {
          name: 'Frozen Yogurt',
          calories: 159,
          fat: 6.0,
          carbs: 24,
          protein: 4.0,
          iron: '1%'
        }, 
        {
          name: 'Ice cream sandwich',
          calories: 237,
          fat: 9.0,
          carbs: 37,
          protein: 4.3,
          iron: '1%'
        }, 
        {
          name: 'Eclair',
          calories: 262,
          fat: 16.0,
          carbs: 23,
          protein: 6.0,
          iron: '7%'
        }, 
        {
          name: 'Cupcake',
          calories: 305,
          fat: 3.7,
          carbs: 67,
          protein: 4.3,
          iron: '8%'
        }, 
        {
          name: 'Gingerbread',
          calories: 356,
          fat: 16.0,
          carbs: 49,
          protein: 3.9,
          iron: '16%'
        }, 
        {
          name: 'Jelly bean',
          calories: 375,
          fat: 0.0,
          carbs: 94,
          protein: 0.0,
          iron: '0%'
        }, 
        {
          name: 'Lollipop',
          calories: 392,
          fat: 0.2,
          carbs: 98,
          protein: 0,
          iron: '2%'
        }, 
        {
          name: 'Honeycomb',
          calories: 408,
          fat: 3.2,
          carbs: 87,
          protein: 6.5,
          iron: '45%'
        }, 
        {
          name: 'Donut',
          calories: 452,
          fat: 25.0,
          carbs: 51,
          protein: 4.9,
          iron: '22%'
        }, 
        {
          name: 'KitKat',
          calories: 518,
          fat: 26.0,
          carbs: 65,
          protein: 7,
          iron: '6%'
        }
      ]
    }
  },
  methods: {
    onBagClick(id) {
      const isTextHighlighting = window.getSelection().toString().trim() !== '';

      if (!isTextHighlighting) {
        alert("Bag Click");
      }
    }
  }
})
@import url('https://fonts.googleapis.com/css?family=Roboto|Material+Icons');
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.min.js"></script>

<div id="app">
  <v-app id="inspire">
    <v-data-table :headers="headers" :items="desserts" class="elevation-1">
      <template slot="items" slot-scope="props">
        <tr @click="onBagClick(props.item.id)"> 
          <td class="text-xs-left" 
            v-for="header in props.item" 
            :key="header.id">{{header}}</td>
        </tr>
      </template>
    </v-data-table>
  </v-app>
</div>

I'm using window.getSelection() for reading selected texts. If you care about supporting IE 8 (and below), have a look at this post for a fallback text-selection-acquiring approach.

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

8 Comments

I have tried it, but now onBagClick event is not triggered at all. I weirdly sometime when I highlight it get triggered.
I thought you want a text-highlighting action not to fire the method on the TR click?
No I don't. But normal clicking on the row also does nothing.codepen.io/anon/pen/YBNLLy
OK, then why don't we do @click.ctrl.stop on the TD and allow highlighting only when Ctrl key is pressed along?
@JeremyWalters Actually I figured out another possible solution for you. Please check my edits.
|

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.