0

I want to call a unique function according to the user's input on JavaScript. I'm working with Node.js, not HTML inputs. I'll leave an example code that explains my general code's goal. Is there any better approach than I did? What would you recommend to me? I don't want to add all the new functions to Map. I want to turn into dynamic too.

let functions = new Map([
      ["Annually", annually],
      ["Daily", daily],
      ["Weekly", weekly],
    ]);   
    async function choice() {
      const answer = await inquirer.prompt({
        name: "choice",
        type: "list",
        message: "How often do you want to get a notification?",
        choices: ["Annually", "Daily", "Weekly"], //Gets choice from users think it's like a HTML form 
      });
      functions.get(answer.choice)(); // Gets the function from map after that calls the function
    }
    
    async function annually() {
       console.log("Annually works.");
    }
    
    async function weekly() {
       console.log("Weekly works.");
    }
    
    async function daily() {
       console.log("Daily works.");
    }
Enes
  • 23
  • 4
  • The usage of a `Map` is totally fine and appropriate. Why do you feel it's not "dynamic"? Would you expect *any* function you declare in your module to be callable - including `choice()` itself? – Bergi Jul 23 '22 at 15:49
  • You can pass `choices: Array.from(functions.keys())` to avoid some duplication – Bergi Jul 23 '22 at 15:50

3 Answers3

0

The way you are accomplishing this seems like it would work, but I think there is a better way to do this that is more readable.

function handleDaily(){
    console.log("daily works");
}

function handleWeekly(){
    console.log("weekly works");
}

function handleAnnually(){
    console.log("annually works");
}

var CHOICE_LIST = [];
const CHOICES = [
    {value: "Daily", handle: handleDaily},
    {value: "Weekly", handle: handleWeekly},
    {value: "Annually", handle: handleAnnually},
];

//Builds choice list based off of CHOICES array
for(let i = 0; i < CHOICES.length; i++){
    CHOICE_LIST.push(CHOICES[i].value);
}

function evalInput(input) {
    for(let i = 0; i < CHOICES.length; i++){
        if(input === CHOICES[i].value){
            CHOICES[i].handle();
            break;
        }
    }
}

async function getChoice(){
    const answer = await inquirer.prompt({
        name: "choice",
        type: "list",
        message: "How often do you want to get a notification?",
        choices: CHOICE_LIST
    });

    evalInput(answer.choice);
}

No need to store the functions in a map unless you really need to. I also removed the async keyword from your functions that were not awaiting anything.

Jaxon Crosmas
  • 397
  • 2
  • 13
  • Your approach is fine but I doesn't want to add every function to switch case. When user gives the answer it automatically calls the function. You're right about async function thing. My main code works with async await that's why I put async. – Enes Jul 23 '22 at 08:32
  • Noted. I made some improvements to my answer. I think this approach is much more readable as we can tell exactly what choices are available and which function is executed just by looking at the `CHOICES` object. This approach also allows you to have more control over your choice values instead of relying on object keys. – Jaxon Crosmas Jul 23 '22 at 11:07
  • That `switch` doesn't really make sense. All the cases are looking the same. Why not just use a loop? And you don't need to make `CHOICES` an object either, an array of `{VALUE, HANDLE}` objects would suffice. – Bergi Jul 23 '22 at 15:47
  • 1
    @Bergi Those are good points. I have made edits to my answer as per your suggestions. – Jaxon Crosmas Jul 23 '22 at 16:08
0

i think this solution is better

const funcs = {
    annually: async () => { // you can change "annually" to anything
        console.log('Annually works.')
    },
    weekly: async () => {
        console.log('Weekly works.')
    },
    daily: async () => {
        console.log('Daily works.')
    },
}

async function choice() {
    const answer = await inquirer.prompt({
        name: 'choice',
        type: 'list',
        message: 'How often do you want to get a notification?',
        choices: Object.keys(funcs),
    })
    await funcs[answer.choice]()
}

  • 1
    that's the best way to solve it I guess. I tried it on my main code and it works! thanks a lot – Enes Jul 23 '22 at 09:00
-2

If these functions are in global object's scope you can do this:

var fn = answer.choice.toString();
if (global[fn] === "function") {
    global[fn]();
  }

If its in a module and you know the module exports

var someExports = require('./someExportsFile.js');
Object.keys(someExports)[fn];

PS:

If this was in browser, you could have used

var brFn = window[fn)];
if (typeof brFn === "function") brFn();
Tintin
  • 2,853
  • 6
  • 42
  • 74