kike
kike

Reputation: 738

How to change dynamically the @click method in vue

I have the need of changing the method that a button executed dynamically. In Javascript, it will be as easy as giving the button and id, for example id="my-button", and then do

document.getElementById("my-button").setAttribute("onclick", "theNewMethodToExecute()")

And just like that, the button will execute the new method. How can I do that in Vue.js?

I have a simple mini-project to show my problem:

HTML:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script src="./ts/generated/logic.js" defer></script>
  </head>
  <body>
    <div class="" id="app">
      <p class="">My number is:</p>
      <button @click="methodToExecute"></button>
    </div>
  </body>
</html>

index.ts (I write my Vue app in TypeScript instead of JavaScript, and I use Webpack and npm to compile my result, which compiles to a file called logic.js)

import Vue from 'vue'

const myApp = new Vue({
    data() {
        return {
            methodToExecute: "doNothing",
        };
    },
    methods: {
        doNothing() {
            console.log("Dong nothing...")
            this.methodToExecute = "doSomethingElse"
        },
        doSomethingElse() {
            console.log("Doing something else...")
        },

    },
});

myApp.$mount("#app");

In this case I tried with a property but that not work.

Note: I am aware that I can conditionally change the method like this:

v-on="{click: condition ? doWhenTrue : doWhenFalse}"

But the logic I have is much more complex, and I need to change the method programatically, the way I can do in JavaScript, How is that possible with Vue?

Upvotes: 0

Views: 971

Answers (1)

t56k
t56k

Reputation: 6981

Why don't you put the condition inside the method and pass an argument to it? I'm not sure on what you're trying to achieve but something like this would work for your use case.

<a @click="doNothingOrSomething(condition)"></a>

methods: {
    doNothingOrSomething(arg) {
        if (arg === 'something') {
            console.log("Doing nothing...")
        } else console.log("Doing something else...")
    }
}

Using that reasoning, the result will be:

import Vue from 'vue'

const myApp = new Vue({
    data() {
        return {
            argument: "",
        };
    },
    methods: {
        doNothingOrSomething() {
            switch (this.argument) {
                case "method1": {
                    console.log("Is method 1")
                    this.argument = "method2"
                    break;
                }
                case "method2": {
                    console.log("Is method 2")
                    this.argument = "method3"
                    break;
                }
                case "method3": {
                    console.log("Is method 3")
                    this.argument = "method1"
                    break;
                }
                default: {
                    console.log("default")
                    this.argument = "method1"
                    break;
                }
            }
        }
    },
});

myApp.$mount("#app");

and the HTML:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script src="./ts/generated/logic.js" defer></script>
  </head>
  <body>
    <div class="" id="app">
      <p class="">My number is:</p>
      <button @click="doNothingOrSomething"></button>
    </div>
    <script></script>
  </body>
</html>

And that makes it work dynamically!

Upvotes: 2

Related Questions