Subscribe on changes!

Vue 3 calling method dynamically without 'this'

avatar
Apr 3rd 2023

What problem does this feature solve?

Not being able to dynamically call an exported function from a composable in vue3 anymore.

Tried:

const a = this[props.type](b) // Not available in composition api and must be a local function when used in options api
const a = window[props.type](b) // Not available in vue
const t = props.type
const a = (t) => {
  this[props.type](b) // Returns a string
}
const a = sleep.call(b) // Works, but function name is not dynamic
Promise.resolve(a).then((result) => {
  return result == result ? result : { error: `${props.type}(${b})` } // Asynchronous call
})

See also https://stackoverflow.com/questions/75258344/vue-3-calling-method-dynamically-without-this

What does the proposed API look like?

Introduce the window object or perhaps a new call function

window["sum"]([1,2]) // Returns 3
call("sum", [1,2]) // Returns 3
avatar
Apr 3rd 2023

You example fels very i complete, also your stackoverflow question has an accepted answer so i dont really get what you are asking for.

One thing i can tell you is that we will definitely not put anything on window.

avatar
Apr 6th 2023

It should be quite obvious.

In vue2 it was possible to call a function by arguments. this[function][arguments] // Only works for local methods and global functions provided by a mixin

In vue3 there is no mixins anymore. There is composables and plugins. Therefore using this will not work for vue3, also not with the options api unless it's a local method.

The stackoverflow answer only offers a solution for a local method inside a component. I am looking for a solution for calling a global function inside a composable.

If window is not an option perhaps provide a call function

Something like call("sum", [1,2]) // Returns 3

avatar
Apr 6th 2023

In vue3 there is no mixins anymore. There is composables and plugins. Therefore using this will not work for vue3, also not with the options api unless it's a local method.

There are mixins in Vue 3, but only for Options API, because Composition API + composables is meant to improve on Options API + mixins, where there latter has a multitude of drawbacks.

The stackoverflow answer only offers a solution for a local method inside a component. I am looking for a solution for calling a global function inside a composable.

You can use the same solution for global methods, provided you make those global methods available through a composable (or multiple).

Yes, you will, somewhere, have to create this map object. But that's the way it works with Composition API. It's in places more verbose by design, to be more explicit.

avatar
Apr 6th 2023

Can you provide an example? I tried many things but I didn't manage to dynamically call a function inside a composable.

avatar
Apr 6th 2023
// imagine these as globally shared functions that you might have added through a global mixin when using Options API.
export const useSum () => (a, b)  => a +b
export const useMultiplication () => (a, b)  =>  a * b
<script setup>
import { useSum, useMultiplication } from '../composables/math.js'
const props = defineProps({
  type: String // could be 'sum' | multiply
})

const mathMethods = {
  sum: useSum()
  multiply: useMultiplication()
}

const callMathMethod(a, b) {
  return mathMethods[props.type](a, b)
}
</script>

that whole logic itself could also be extracted into a composable of its own and expose a call function only.

If you need more specific help, visit our discord at chat.vuejs.org or open a thread in this repo's "Discussions" section

avatar
Apr 7th 2023

@LinusBorg This workaround still requires declaring functions. Why not consider support for this functionality which is also possible with vue2 and js?

The workaround should be without the arguments when declaring the functions. @LinusBorg Can you update?

const mathMethods = {
  sum: useSum // Returns the function 
  multiply: useMultiply() //  Returns the result of multiply() instead of the actual function
}
avatar
Apr 7th 2023

This workaround still requires declaring functions.

Not sure what that means. When you write a mixin, you also have to write the mixin. Here, I write composables instead. Is this about the need to explicitly import and call them? That's kind of the point, being explicit.

Why not consider support for this functionality which is also possible with vue2 and js?

It's still possible in Vue 3 with Mixins and Options API. You have the choice. CompositionAPI hits a different trade-off between explicitness and convenience here - it's a trade-off we made consciously for an overall better code architecture, even if it's a bit cumbersome for this specific usecase. You can accept that tradeoff, or go back to Options API and mixins.

The workaround should be without the arguments when declaring the functions. @LinusBorg Can you update?

Please look at the example again. Each of the composable is a function returning another function that actually takes the arguments. Of course that does not make sense for something as simple as a sum function (you would probably just import that directly as a utility), but it's the general pattern for composables so I stuck to it here for the example.

avatar
Apr 7th 2023

I tested it. Your workaround works but you should remove the '()' to return the function instead of the result.

const mathMethods = {
  sum: useSum
  multiply: useMultiply
}

The feature request is very simple. Provide an object/function to dynamically call a function.

Something like: call("sum", [1,2]) // Returns 3 from the sum function

If this is not possible I will use the workaround that you provided. I prefer composables over mixins so I will not switch back 2 options api again.

avatar
Apr 7th 2023

I tested it. Your workaround works but you should remove the '()' to return the function instead of the result.

Nope. If they are composables, they need to be called to get the actual function:

https://play.vuejs.org/#eNp1UktTwjAQ/is7ubTVGpQjA4yOZ04ejYe0BKjmNXkwOgz/3U1ToDB6Snb322+/fRzIi7V0HwWZkblvXWcDeBGiXTLdKWtcgAM4sYEjbJxRUCC0GIWiF29R1eldRRk6K7uWh87ocwKdKB529NNjGtOt0T5A8qxE2Jm1hwUcmAbwUc0GtrKqk0dlvp/efU1eVkwfL3Qtl3J1pkTGUvU/zZWogdfQVLBY5joOm3N6rOD9Av4oe3BPnql1VI1wT8iJQygfMTT2T0f+U2TH9VqmNl5R7VcSQynlbusvGhLQSEGl2ZbX2ssC51DUp7J0z2XEFoZq2ayyvvkkrwsXNQ9CWcmDSP9O2xhg/6DMWsgFIwMVI5P/o9Mh2sQQcHXPbZKO0eteGEEMAJoAqX5Goy8ZZwmkJsPC8aTEd38neTJ5u2ki/SjyrCF9Odw3TN+Cbw7qjzxMvIOGHH8Bq2r0Ag==

The feature request is very simple. Provide an object/function to dynamically call a function.

It sounds very simple to you, but doesn't fit with the way composition API works, so it's not gonna happen, very likely.

If this is not possible I will use the workaround that you provided.

It would be my recommendation to do that, yes.