mafraqs
mafraqs

Reputation: 173

How to bind method by passing the method name via a variable to @click

I'm still quite new to vuejs and was watching one of many videos online to teach myself, when a question came to my mind.

With vuetify I build a navigation drawer that is looping (v-for) through a list of menu items and printing the details of the items with v-if.

Now for the question I have: In vuejs, is there a way to bind a method from vues 'methods' like singOut() to an @click by passing the method with a variable.

@click="item.method" and @click="{item.method}" didn't work for me.

Clearification: There could be more methods than singOut() I would want to bind to @click. Because of that I'm looking for a more dynamic way to bind the method.

Thanks in advance :)

new Vue({
	el: '#app',
  data: {
  	items: [
      { icon: "lightbulb_outline", text: "Notes", path: '/tools/notes' },
      { icon: "access_alarm", text: "Worktime", path: '/tools/worktime' },
      { divider: true },
      { heading: "Labels" },
      { icon: "add", text: "Create new label" },
      { divider: true },
      { heading: "Account" },
      { icon: "lock_open", text: "Login", path: '/signin' },
      { icon: "mdi-account-plus", text: "Sign Up", path: '/signup' },
      { icon: "mdi-logout", text: "Sign Out", method: 'singOut()' },
      { divider: true },
      { icon: "settings", text: "Settings", path: '/' },
      { icon: "chat_bubble", text: "Trash", path: '/' },
      { icon: "help", text: "Help", method: 'sendAlert("Really want to delete?")' },
      { icon: "phonelink", text: "App downloads", method: 'sendAlert("Leaving the app")' },
      { icon: "keyboard", text: "Keyboard shortcuts", path: '/' }
    ]
  },
  methods: {
  	navigateTo(path) {
      if (path) {
        this.$router.push(path);
      } else {
        this.$router.push('/');
      }
    },
    singOut(){
      this.$store.dispatch('singOut');
    },
    sendAlert(msg) {
    	alert(msg);
    }
  }
});
ul {
  list-style: none;
}
<script src="https://unpkg.com/vue/dist/vue.js"></script>

<div id="app">
  <ul>
    <li v-for="(item,i) in items">
      <span v-if="item.heading" :key="i"><b>{{item.heading}}</b></span>
      <span v-else-if="item.divider" :key="i">--------</span>
      <span v-else-if="item.method" @click="item.method" :key="i" style="cursor:pointer;">{{item.text}} (+ @click->Method)</span>
      <span v-else> {{item.text}} -> {{item.path}}</span>
    </li>
  </ul>
</div>

Upvotes: 2

Views: 1389

Answers (2)

Traxo
Traxo

Reputation: 19022

Codepen

Split method in method-name and argument properties. You can create for example call method which calls passed function with passed arguments @click="call(item.method, item.args)".

<v-btn v-for="item in items" :key="item.id" @click="call(item.method, item.args)">
  {{item.text}}
</v-btn>

items: [
  ...
  { id: 5, text: "5", method: "methodTwo", args: ["Another message", 123] },

methods: {
  call(method, args = []) {
    this[method](...args)
  },

Make custom assertions as needed.
Any flaw in this approach?

Upvotes: 2

Ru Chern Chong
Ru Chern Chong

Reputation: 3756

Since you already have singOut() in your methods: {}, in your html for @click, just use @click="singOut(item.method)"

Your singOut() must be able to accept the params.

singOut(method) {
  // method here
  console.log(method)
}

I think this is not what you want to achieve because your method in the object consists of functions.

Using your current data:

items: [
  { icon: 'help', text: 'Help', method: 'Some method here', alert: 'Really want to delete?' }
]

What I suggest you could do is

  • Have another property alert and set the string to it.
  • Bind the @click event to a method with the item as the params; use that method to trigger an alert() with the alert property value in it.

Example:

singOut(item) {
  // handle the alert if it exists
  if (item.alert) {
    this.sendAlert(item.alert)
  } 

  // handle the method value
  console.log(item.method)
}

Upvotes: 0

Related Questions