Home > Net >  JS Vue3: Modal dialog: call parameterized function returned by function
JS Vue3: Modal dialog: call parameterized function returned by function

Time:09-24

First of all, I am not sure whether this is a Vue thing or just a JavaScript related question. I wrote some code which finally works, but I don't know why. Maybe you can enlighten me.

I created a "dialog window" component. It is a simple (modal) dialog which takes a function as a parameter. If the user clicks OK the function is called - like "Do you really want to delete that file?" Cancel or OK.

The function I pass to the component has sometimes a parameter itself. So I want to pass the already parameterized function as a parameter to my component. I achieve this by wrapping the function in an arrow function which returns the parameterized function which then can be called.

The idea of this concept in pure JS looks like this:

//the function to be finally executed
function say(message) {
  document.getElementById("output").innerHTML = message;
}

//the parameterized function inside of an arrow function (as a variable)
const sayhelloworld = () => say("hello world");

//finally I call the arrow function which 
//returns the parameterized function and calls this one as well
function start() {
  sayhelloworld()(); //this is the core of my question: the double brackets!
}

So I need double brackets. The first () returns the function inside and the second () calls it. And it does work exactly like this: https://codepen.io/keztur/pen/powaLJN

Now let's turn to vue:

I open my dialog component with an event bus (sorry about that) and pass a parameter object including the function parameter. (I use Vue 3 - so behind my EventBus object is actually the 'mitt' library: https://github.com/developit/mitt)

//component calling the dialog and passing the function parameter 
//(as a part of a parameter object)
EventBus.emit("OpenDialog", {
    header: "Delete file",
    body: "Do you really want to delete that file?",
    function: () => this.Delete(file_id)
});

Modal-component:

  data() {
    return {
      show: false,
      ModalProps: {
        header: "",
        body: "",
        function: ""
      }
    };
  },

//inside of the modal component this function is called 
//if the user clicks any of the two buttons (cancel or OK)
  methods: {
    clicked(button) {
      if (button === 'ok' && typeof this.ModalProps.function === 'function') {
        this.ModalProps.function(); //why does this work ...
       //this.ModalProps.function()(); //...but not this?
 //the second line does call the function but also throws an error afterwards
      }
      this.show = false; //modal is closed
    }
  },
... etc.

So at first I was using the double brackets as in my JS example above. And the function was called properly but the second "execution" backets obviously threw an error:

[Vue warn]: Unhandled error during execution of native event handler 
  at <Modal> 
  at <App>

But since I deleted the second bracket, everything works just fine.

So my question is: Why is in Vue the function inside my arrow function called right away and not just returned by reference?

CodePudding user response:

Your first example doesn't work. It only should be sayhelloworld();. Open the (browser or codepen) console when running it. It will say:

TypeError: sayhelloworld() is not a function 

It only looks like it's working, because there is no more to do after the error. Try adding, for example, alert("Done") after sayhelloworld()(); and you'll notice that the alert is never shown.

The difference in Vue is that Vue catches and displays the error.

sayhelloworld (and this.ModalProps.functionin your Vue example) are just normal (references to) functions, which don't return anything. There is no(*) difference between

const sayhelloworld = () => say("hello world");

and

const sayhelloworld = function() {
  say("hello world");
}

and

function sayhelloworld() {
  say("hello world");
}

You would use ()() if the function returns a function itself, for example:

function sayhelloworld() {
  const innerFunction = function () {
    say("hello world");
  }
  return innerFunction;
}

or

function sayhelloworld() {
  return () => say("hello world");
}

or even

const sayhelloworld = () => () => say("hello world");

Again these examples do the same thing(*).


(*) They are not completely identical, mostly regarding hoisting and how the handling of this inside the function, but that isn't relevant here.

  • Related