1

Couldn't find a proper name for the title, will be glad if someone figures out a better name.

I have a component which represents a product card. The whole component is wrapped in <router-link> which leads to product page.

However I have another case, when I do not need the component to lead to a product page, but instead I need to do some other action.

The only solution I found is to pass a callback function as a prop, and based on this, do something like:

<router-link v-if="!onClickCallback">
    ... here goes the whole component template ...
</router-link>
<div v-if="onClickCallback" @click="onClickCallback">
    ... here again goes the whole component template ...
</div>

How can I do this without copy-pasting the whole component? I tried to do this (real code sample):

  <router-link class="clothing-item-card-preview"
               :class="classes"
               :style="previewStyle"
               :to="{ name: 'clothingItem', params: { id: this.clothingItem.id }}"
               v-on="{ click: onClick ? onClick : null }">

However I got this: Invalid handler for event "click": got null

Plus not sure if it's possible to pass prevent modificator for click and this just looks weird, there should be a better architectural solution

3 Answers 3

1

Commenting on the error, you could use an empty function instead of null, in the real code snippet

  <router-link class="clothing-item-card-preview"
           :class="classes"
           :style="previewStyle"
           :to="{ name: 'clothingItem', params: { id: this.clothingItem.id }}"
           v-on="{ click: onClick ? onClick : null }">
Sign up to request clarification or add additional context in comments.

1 Comment

Yes, but I cannot use ".prevent" in v-on, I guess... so router-link will behave as a link in any case
1

This should works (replace a for "router-link" then insert right properties) Further infos :

  • https://fr.vuejs.org/v2/guide/components-dynamic-async.html
  • v-bind is simply an Object where each keys is a props for your component, so here, I programmatically defined an object of properties depending on the wrapper (router link or a simple div). However we cannot do this for events (of course we could create our own event listener but it's a little bit tricky) so I simply but an handle method.

new Vue({
    el: "#app",
    data: {
		  products : [{onClickCallback : () => { alert("callback"); return true;}}, {}, {}]
    },
    methods : {
        handleClick(product, event) {
            if (!product.onClickCallback) return false
            product.onClickCallback()
            return true
        },
        getMyComponentName(product) {
            if (product.onClickCallback) return "div"
            return "a"
        },

        getMyComponentProperties(product) {
            if (product.onClickCallback) return {is : "div"}
            return {
                is : "a",
                href: "!#"
            }
        }
    }
})
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
    <component
        v-for="(product, index) in products"
        :key="index"
        v-bind="getMyComponentProperties(product)"
        @click="handleClick(product, $event)"
    >
        <div class="product-card">
            <div class="product-card-content">
                <span v-show="product.onClickCallback">I'm a callback</span>
                <span v-show="!product.onClickCallback">I'm a router link</span>
            </div>
        </div>
    </component>
</div>

Comments

0

Do you have to use a <router-link>? If it can safely be a <div>, you could use something like

<div @click="handleClick" ...>
  <!-- component template -->
</div>

and

methods: {
  handleClick (event) {
    if (this.onClickCallback) {
      this.onClickCallback(event)
    } else {
      this.$router.push({ name: 'clothingItem', ... })
    }
  }
}

See https://router.vuejs.org/guide/essentials/navigation.html

3 Comments

This way user cannot open this product in a new tab. The this is that this has to be a link, so that I can open multiple products in multiple tabs
@Victor ah, you make an excellent point but what about the other case, where you need the click handler?
When I need click handler it does not matter if it's a div or link :) But just to be a bit more consistent I'd be using links everywhere

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.