skip to Main Content

An application has some buttons on a screen that should execute different functions when clicked. It goes like a little like this:

<template>
<ul>
<li v-for="MenuItem in MenuItems">
  <button type="button" @click.prevent="handleClick({Function: MenuItem.Function.Name, Params: MenuItem.Function.Params })">
              {{ MenuItem.Label }}
  </button>
</li>
</ul>
</template>

<script setup>
const MenuItems = [
{
              Label: `Edit`,
              Function: {
                Name: `editItem`,
                Params: {
                  ItemID: 1
                }
 },
{
              Label: `Delete`,
              Function: {
                Name: `deleteItem`,
                Params: {
                  ItemID: 1
                }
 }
]

function handleClick({Function, Params}) {
   Function.apply(Params) // throws not a function error
   eval(Function+"()")    // throws not a fuction error
}

function editItem(){
console.log(`edit item`);
}

function deleteItem(){
console.log(`about to delete item`);
}
</script>

All I want to do is run whatever has been passed to the Function argument in handleClick() and also include the Params argument as an argument to the Function that needs to be executed e.g. editItem(1) or deleteItem(1);

Trying apply() and eval() don’t seem to work and throws an error that Uncaught TypeError: Function.apply is not a function. I am using VueJS as the framework, but this is really a Javascript question.

3

Answers


  1. Make the functions as methods of an object and call the methods:

    Playground

    const Functions = {
      editItem,
      deleteItem
    };
    
    function handleClick({Function, Params}) {
      Functions[Function](Params);
    }
    
    
    Login or Signup to reply.
  2. I reviewed your code.
    Please try with this codebase.

    <template>
      <ul>
        <li v-for="MenuItem in MenuItems" :key="MenuItem.Label">
          <button type="button" @click.prevent="handleClick(MenuItem.Function)">
            {{ MenuItem.Label }}
          </button>
        </li>
      </ul>
    </template>
    
    <script setup>
    function editItem(params) {
      console.log(`Editing item with ID: ${params.ItemID}`);
    }
    
    function deleteItem(params) {
      console.log(`Deleting item with ID: ${params.ItemID}`);
    }
    
    const MenuItems = [
      {
        Label: `Edit`,
        Function: {
          Name: editItem, // Pass the actual function reference
          Params: {
            ItemID: 1
          }
        }
      },
      {
        Label: `Delete`,
        Function: {
          Name: deleteItem, // Pass the actual function reference
          Params: {
            ItemID: 1
          }
        }
      }
    ];
    
    function handleClick(FunctionObject) {
      const { Name, Params } = FunctionObject;
      Name(Params); // Invoke the function with parameters
    }
    </script>
    

    Thanks

    Login or Signup to reply.
  3. The Function property in your MenuItems array is not a reference to an actual function. It’s a string (editItem, deleteItem), and you cannot call or apply a string like a function.

    To fix the problem, you can pass actual function references instead of strings in the MenuItems array. Here’s the corrected code:

    <template>
      <ul>
        <li v-for="MenuItem in MenuItems" :key="MenuItem.Label">
          <button 
            type="button" 
            @click.prevent="handleClick(MenuItem.Function, MenuItem.Function.Params)">
            {{ MenuItem.Label }}
          </button>
        </li>
      </ul>
    </template>
    
    <script setup>
    function editItem(ItemID) {
      console.log(`edit item with ID: ${ItemID}`);
    }
    
    function deleteItem(ItemID) {
      console.log(`about to delete item with ID: ${ItemID}`);
    }
    
    // Pass actual function references in the MenuItems array
    const MenuItems = [
      {
        Label: 'Edit',
        Function: {
          Name: editItem,
          Params: { ItemID: 1 }
        }
      },
      {
        Label: 'Delete',
        Function: {
          Name: deleteItem,
          Params: { ItemID: 1 }
        }
      }
    ];
    
    // Use `Function` directly as a function reference
    function handleClick(Function, Params) {
      Function(Params.ItemID);
    }
    </script>
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search