Home > Back-end >  Event only firing as inline JS statement
Event only firing as inline JS statement

Time:04-25

I have the following code in a Nuxtjs app in SSR mode.

<Component
      :is="author.linkUrl ? 'a' : 'div'"
      v-bind="!author.linkUrl && { href: author.linkUrl, target: '_blank' }"
      @click="author.linkUrl ? handleAnalytics() : null"
    >

The click event in case it's an a tag, will only fire if it's written as handleAnalytics(), but handleAnalytics will not work.

Don't get me wrong the code is working, but I don't understand why.

CodePudding user response:

In javascript functions are a reference to an object. Just like in any other language you need to store this reference in memory.

Here are a few examples that might help you understand on why its not working:

function handleAnalytics() { return 'bar' };

const resultFromFunction = handleAnalytics();
const referenceFn = handleAnalytics;

resultFromFunction will have bar as it's value, while referenceFn will have the reference to the function handleAnalytics allowing you to do things like:

if (someCondition) {
  referenceFn();
}

A more practical example:

function callEuropeanUnionServers() { ... }
function callAmericanServers() { ... }

// Where would the user like for his data to be stored
const callAPI = user.preferesDataIn === 'europe' 
  ? callEuropeanUnionServers
  : callEuropeanUnionServers;

// do some logic
// ...

// In this state you won't care which servers the data is stored.
// You will only care that you need to make a request to store the user data.
callAPI();

In your example what happens is that you are doing:

@click="author.linkUrl ? handleAnalytics() : null"

What happens in pseudo code is:

  1. Check the author has a linkUrl
  2. If yes, then EXECUTE handleAnalytics first and then the result of it pass to handler @click
  3. If not, simply pass null

Why it works when you use handleAnalytics and not handleAnalytics()?

  1. Check the author has a linkUrl
  2. If yes, then pass the REFERENCE handleAnalytics to handler @click
  3. If not, simply pass null

Summary

When using handleAnalytics you are passing a reference to @click. When using handleAnalytics() you are passing the result returned from handleAnalytics to @click handler.

CodePudding user response:

With classical event binding (@click="handleAnalytics), Vue will auto bind it for you because it sees it's a function.

But when provided a ternary condition, it's not auto binded but wrapped into a anonymous function instead. So you have to call it with parenthesis otherwise you're just returning the function without executing it.

To be clearer, you can write it this way: @click="() => author.linkUrl ? handleAnalytics() : null"


Note: when having a dynamic tag component, I'd suggest to use the render function instead.

This is an advanced technique, but this way you won't bind things to an element that doesn't need it (without having the kind of hack to return null).

Example:

export default {
  props: {
    author: { type: Object, required: true },
  },
  render (h: CreateElement) {
    const renderLink = () => {
      return h('a', {
        attrs: {
          href: author.linkUrl,
          target: '_blank',
        },
        on: {
          click: this.handleAnalytics 
        },
      )
    }

    const renderDiv = () => {
      return h('div')
    }
    
    return this.author.linkUrl ? renderLink() : renderDiv()
  }
}

Documention: Vue2, Vue3

  • Related