in an existing implementation (can't change the structure much), i'm trying to call a function which is nested inside another function:
function outer(innerFunction, obj) {
//TODO: call innerFunction here, passing obj as first parameter
function inner1(obj) {
alert(obj.key);
}
}
outer('inner1', {key:'value'});
jsfiddle is here: http://jsfiddle.net/tbyyw/
i've alreay thought about using eval(), but i don't know how to pass an object - and they say 'eval is evil' ;)
another solution i've come up with is checking the innerFunction string, but this means i have to know which inner functions exist (besides, adding new functions would mean having to write extra checks then):
if(innerFunction == 'inner1') inner1(obj);
so is there another way without changing the overall implementation?
Without changing the overall structure eval appears to be the only option:
function outer(funcName, obj) {
var func = eval(funcName);
func(obj);
function inner1(obj) {
alert(obj.key);
}
}
There's nothing particularly "evil" about eval as long as you have full control over the code, but if you want, you can insert an additional security check:
if (funcName.match(/\W/))
throw "invalid function name!";
var func = eval(funcName);
This will raise an exception if someone tries to pass anything else than a simple identifier, i.e. a function name.
Is this what you wanted?
function outer(innerFunction, obj) {
var fn = {
inner1: function (obj) {
alert(obj.key);
}
};
fn[innerFunction](obj);
}
outer('inner1', {key:'value'});
http://jsfiddle.net/tbyyw/1/
A simple switch statement would be least intrusive. Or is the function name completely dynamic?
function outer(innerFunction, obj) {
switch (innerFunction) {
case "inner1": inner1(obj); break;
}
function inner1(obj) {
alert(obj.key);
}
}
outer('inner1', {key:'value'});
Related
I'm a complete newbie to Javascript so I don't know what its capable of. Any help would be much appreciated!
As the title suggests, I'm trying to pass an argument from a function to name another function inside of it. The method below doesn't work for obvious reasons but I think it conveys what I'm trying to do. The function names need to be very specific for the project I'm working on.
function mainFunc(param1) {
function param1() {}
}
Thanks!
Edit: The software that we are going to start using to go paperless at my work uses a javascript scripting engine. In order for me to do simple things such as:
If at least one of the checkboxes in section A is checked, then you must check at least one checkbox in section B.
I would have to write a function for each and every checkbox field on the form due to the way the software works, the function name has to be specific to the name we assign to the checkbox through their GUI. I was hoping to write a function that writes another function with the specific name, and calls the said function.
function mainFunc(funcName) {
function 'funcName'() {
//do stuff;
}
'funcName'()
}
mainFunc('Checkbox1')
Maybe this will help clarify a little more on what I'm trying to do. Sorry for not being clear the first time around.
You have many options to solve your problem
one option is to return an object with the functions named using the parameters passed to mainFun look at the example below
function mainFunc(param1,param2) {
return {
[param1]:function () {
console.log(" I am function from " + param1)
},
[param2] : function () {
console.log("I am function from " + param2) ;
}
}
}
let hello = 'hello' ;
let greet = 'anything' ;
let functions = mainFunc(hello,greet);
functions['hello']();
functions['anything']();
functions[hello]();
functions[greet]();
if you have many parameters to the mainFun you can also solve it using the arguments object like the example below
function mainFun(par1) {
let myObj = {};
for(let i = 0 ; i<arguments.length;i++){
console.log(arguments[i]);
myObj[arguments[i]] = ()=> {
console.log('You call me from ' + arguments[i]);
}
}
return myObj ;
}
let functions = mainFun('a','b','c','d');
functions['a']();
functions['b']();
functions['c']();
functions['d']();
I am using the below function, I am trying to generalize the function without using hardcoded values. How i can achieve it?
function ChangeIDToString(strCondition,id)
{
if (strCondition.indexOf("AssignedTo") > -1)
return GetUserName(id)
else if (strCondition.indexOf("ClaimStatusId") > -1)
return GetClaimStatus(id)
else if (strCondition.indexOf("ClaimTypeId") > -1)
return GetClaimType(id);
else
return id;
}
It would be nice to see what your functions do.
But in your functions, you can declare:
var j={"id":"return of your function string here"};
JSON.stringify(j); // '{"id":"return of your function string here"}'
You could create an object of functions, and then call a function named by strCondition using bracket notation and dynamic property name. Something like this:
var objOfFunctions = {
GetUserName: function (id) {...},
GetClaimStatus: function (id) {...},
GetClaimType: function (id) {...}
};
function ChangeIDToString(strCondition,id) {
if (!objOfFunctions.hasOwnProperty(strCondition)) {
return id;
}
return objOfFunctions[strCondition](id);
}
In a case you already have a lot of calls to the functions in objOfFunctios somewhere else in your code, you can populate that object with references too.
A live demo using references in objOfFunctions at jsFiddle.
EDIT
After discovered that you've asked this same question before, it looks like my original answer still hardcodes too much. (Your comment to void's similar answer.)
The goal can still be achieved by passing a function reference instead of a string to ChangeIDToString. Though you will lose the ability to check, which function will be called. Like this:
function ChangeIDToString(refCondition,id) {
if (typeof refCondition !== 'function') {
return id;
}
return refCondition(id);
}
// Invoke example
console.log(ChangeIDToString(GetClaimType, 'some_ID'));
A demo at jsFiddle.
If the string can't be replaced with a reference, your last resort is to use eval(), but it's strongly recommended not to do so.
An eval demo at jsFiddle.
You weren't clear as to where/how you wanted JSON to fit into your solution, but if you are saying that there will definitely be one of those 3 strings passed into the function and which function gets called from there is based on which string is passed in, then you could leverage the fact that all arguments are optional in JavaScript. As long as your function only gets called with 2 arguments (id and one of the others), this would do it:
function ChangeIDToString(id, user, claimStatusId, claimTypeId)
{
if (user !== null)
return GetUserName(id)
else if (claimStatusId !== null)
return GetClaimStatus(id)
else if (claimTypeId !== null)
return GetClaimType(id);
else
return id;
}
https://jsfiddle.net/m271cpum/ for more complete example.
I have a simple requirement, I need add the same code to hundreds of other JavaScript functions, the code can be executed at the end of the function, is there a handy way of doing it, like attach an function to another function dynamically, I think yes, because JavaScript is so powerful and too powerful, any ideas?
Note, I need dynamically assign new code or function to existing functions without change existing function's code, please give a solid solution, I can do it in hacky way, but no hacky way please!
The first method that comes to mind is simply create another function:
function primaryFunction() {
// ...
utilityMethod();
}
function otherPrimaryFunction() {
// ...
utilityMethod();
}
function utilityMethod() { ... }
Now utilityMethod() gets called from the end of each other primary function.
There's also a method which requires more code refactoring but is better in the long term: classes/prototypes.
Essentially, you have one "constructor" function which takes a number of parameters for the "class" and returns an class-like object:
function constructor(someClassField, anotherField) {
this.aField = someClassField;
this.fieldTwo = anotherField;
return this;
}
Now if you call this and pass some parameters, you get a class out:
var myClass = new constructor("1", "2");
myClass.aField == "1";
myClass.fieldTwo == "2";
So: If you define your utility method as above, then you can use this: for every primary function you instantiate a new instance of the constructor, with the final code looking like this:
function constructor(primaryFunction) {
this.function = primaryFunction;
this.call = function() {
this.function();
utilityMethod();
}
this.call();
return this;
}
function utilityMethod() { ... }
var primaryMethod = new constructor(function() { ... });
The creation of primaryMethod now automatically calls the primary function followed by the utility method, before returning the object so you can re-call both if you want to.
I have the 'phone_dlg_manager' constructor function and its private methods show and init_country_code_combobox. The dialog reference is held in the phone_dlg variable. The show method triggers init_country_code_combobox and I have two options:
1) Explicitly pass the variable country_combobox that the init_country_code_combobox methods needs:
function phone_dlg_manager(ctx, open_dlg_button, edit_ctrl, item)
{
var phone_dlg;
show();
function show()
{
phone_dlg = ctx.application.ui.create_dialog(0, "PhoneEditorDlg");
init_country_code_combobox(phone_dlg.country);
read_to_dialog_controls(this._form_item);
phone_dlg.visible = true;
}
function init_country_code_combobox(country_combobox)
{
country_combobox.items.clear();
country_combobox.items.start_adding();
country_combobox.items.finish_adding();
}
}
2) Since phone_dlg is accessible withing init_country_code_combobox through closure, I can access the property that I need without explicitly passing the variable:
function phone_dlg_manager(ctx, open_dlg_button, edit_ctrl, item)
{
var phone_dlg;
show();
function show()
{
phone_dlg = ctx.application.ui.create_dialog(0, "PhoneEditorDlg");
init_country_code_combobox(phone_dlg.country);
read_to_dialog_controls(this._form_item);
phone_dlg.visible = true;
}
function init_country_code_combobox()
{
var country_combobox = phone_dlg.country;
country_combobox.items.clear();
country_combobox.items.start_adding();
country_combobox.items.finish_adding();
}
}
The second option seems easier to understand when reading code, however it makes the init_country_code_combobox function know more than it needs. Which option should I choose?
Thanks
This is mostly a matter of style. Option 1 is a little cleaner, and more extensible, since you can use init_country_code_combobox() to initialize more than just the one dialog. But if this is unlikely to be necessary, option 2 is not unreasonable.
I'm trying to make a function that get two parameters and do different stuff according to which step it's on.
So it's like a short quest with four steps.
var stp=1;
var vocabulary= new Array();
vocabulary['greatings']= ['привет','здорово','здравствуй'];
vocabulary['grQuestions']= ['как дела','что нового','как здоровье','как поживаешь'];
vocabulary['qrAnswers']= ['нормально как сам','спасибо хорошо','потихоньку','отлично'];
function myMission(stp,str) {
switch (stp) {
case 1:
{
if (jQuery.inArray(str, vocabulary['greatings'])!==-1) {
stp+=1;
$('.stp').html(stp);
$('.answer').html('Привет!');
} else {
$('.stp').html(stp);
$('.answer').html('Не понимаю');
}
}
break;
case 2:
alert("23");
break;
case 3:
alert("24");
break;
}
}
$(document).ready(function() {
$('#checker').click(function() {
var str = $('.yourVoice').val();
myMission(stp,str);
});
});
The problem is that stp always back to 1
how can I fix it?
The problem is that you are passing the value of stp to the function as a parameter. It then operates on its local copy and not the global variable.
To fix it, remove the stp parameter from the function definition and any calls to it.
function myMission(str) { ...
myMission(str);
Why do you complicate yourself using the same name for a global variable var stp=1; and a function argument function myMission(stp,str) ? The variable you're editing is the local one to the function scope, the global is not being affected at all.
If I understood well, you don't need the argument, and should only use the global variable.
function myMission(str) { ... }
When you do stp+=1 inside a function with a parameter with the same name, you are not working anymore with the global var, but you are working on the parameter that actually is a copy of the original var, so you are working on a totally different thing.
The solution can be to change the name of the parameter of the function:
function myMission(stp_another_name,str) {
...
Anyway if you want to work on the global var you can omit to pass it to function as parameter
function myMission(str) {
...
...
myMission(str);
Of course according the purpose of your code