0

I'm working full-stack on a project, and I've run into a bit of a situation that I think I'll need to resolve fully so I can re-use it in future projects (fairly new to Node, but tons of programming languages and syntax under my belt), so a dirty fix might not be the best (eval()?) I have 3 files, here is an example of the logic:

// main.js
const call = require('./test.js');
config = require('config');
configObj = config.get('Site')
sites = Object.keys(configObj);
siteObj = config.get('Site' + "." + sites[0]); // This only calls Amazon, but in the real project it is a dynamic element
var callCommand = "call." + siteObj.functionCall + "(siteObj)"; // evaluates as call.amazon(siteObj)
setTimeout(() => {callCommand;}, 1500);     // This does not work
setTimeout(() => {call.amazon(siteObj);}, 1500);    /// This works
// default.json
{
"Site": {
        "Amazon": {
            "homePage": "https://www.amazon.com/",
            "functionCall": "amazon"
        }
}
// test.js
function amazon(siteObj) {
// some code
console.log("reached the function");
}

Basically, I'm going to be calling different functions from main.js, targeting the test.js. I need the function call to be dynamic, because it is based on the Site's callFunction key. For instance, once there are 10 sites, maybe it would call "call.xxxxxxx(siteObj)", instead. The string creating the call does not seem to be working, I think because it's a String and the line is looking for a function to execute. I get that, but again, I'm fairly new to Node/JS in general and I'm not exactly sure how to even word the question. I thought simply placing the proper text of the function call as a string would cause JS to execute that text, but I guess not.

Am I missing something simple? I know I will need dynamic function calls in the future of this project, and others, so while I can write logic in test.js or main.js to work around THIS example, writing separate function calls for each Site:

if (sites[0]) {call.amazon(siteObj);
if (sites[1]) {call.ebay(siteObj);

for instance, will get cumbersome, as the Sites list will only grow.

Therefore, we created the callFunction key to try and give each object it's exact call.

I'm not sure if it's parenthesis placement, or the way arrow functions work for the setTimeout, or what it is, but I've tried different instances of:

setTimeout(() => {call.$(siteObj.functionCall)(siteObj);}, 1500);     // This does not work
setTimeout(() => {call.$(siteObj.functionCall)(siteObj))); }, 1500) // This does not work

I'm not sure how to use a regular variable, or an object's key properly in this instance to fetch "amazon", especially with the (siteObj) parameter. and things like that. I am hoping more to be able to one-liner it like that SOMEHOW, but I don't know all of the tricks of this language yet.

I've also tried:

var callCommand = "call." + siteObj.functionCall + "(siteObj)"; // evaluates as call.amazon(siteObj)
var codeToExecute = callCommand;
var tmpFunc = new Function(codeToExecute);
setTimeout(() => {tmpFunc(); }, 1500);

With the above, I get "call" is not defined.

It works with the explicit text in there (call.amazon(siteObj)), but I need that "amazon" to be dynamic, preferably called from it's config key (even if I need to turn that key into a json formatted function).

I know this a huge wall of a read, but it is my first post here. Thanks in advance! Hopefully I formatted and named this post correctly without causing too much of a headache, I apologize if I did.

So, am I missing something simple? I feel like I am, but I'm not new to coding at all, and I am alone on this project (no other developers), and I'm trying to keep it good practice without too many, or any, dirty workarounds. Thank you!

1 Answers1

0
setTimeout(() => {callCommand;}, 1500);

That evaluates the string and does nothing.

You can dynamically call the function from the exported object:

call[siteObj.functionCall](siteObj)

This way you access the object with the functions, that is the module exported, using the property that holds the function, and call it

const call = require('./test.js');

Is giving you something similar to

{
  amazon: function() {}
}

Which is just an object

And as you want to dynamically access it, you have to use brackets instead of the dot notation, which allows you to access an object using a variable

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
iunfixit
  • 953
  • 3
  • 15
  • Awesome! This information alone is going to help tremendously. I plugged into the real project using the brackets, and I was able to call the function based on the functionCall key. I will definitely need to remember this syntax. Just to be clear, the function in test.js is being exposed as an object (I forgot to include the module.exports = {amazon} in test.js, but you still knew) CONTAINING a function instead of BEING a function, and that is why I need to grab it that way? – garybracket Sep 09 '21 at 16:28
  • The function isn't "exposed" as an object. `module.exports = {amazon}` is in fact `module.exports = { amazon: amazon }`(just a shorthand). You are exporting a new object, with a property called amazon, and its value is the function you defined, and then you access the object – iunfixit Sep 09 '21 at 16:34
  • Ah! Gotcha! Thank you for the information, I'm looking forward to developing in this language. I'm glad there are such knowledgable people out there that are devoted to helping. You've been a great help! I'd like to buy you a coffee, but I'm not sure if that's allowed here! The business is happy, the wife is happy, I am happy. – garybracket Sep 09 '21 at 17:09
  • You're welcome! I appreciate that, although SO is more focused on directly questions and answers for results so there is nothing like that, it can take a little time to learn the ins and outs of the website – iunfixit Sep 09 '21 at 21:57