This is probably basic... given a fully qualified function name, I'm trying to call it via .apply()
Superficial example
var ns = {
someFunc: function() { console.log('stuff'); }
}
function someTopLevelFunc() { console.log('top level'); }
Given a method that takes the name of that function, us there some way to call the namespaced function?
function theCaller(funcName) {
console.log("Callback name: " + callbackFunctionName)
const callbackFunction = window[callbackFunctionName];
console.log("Type: " + (typeof callbackFunction))
if((typeof callbackFunction) === "function") {
callbackFunction.apply(null, []);
}
}
theCaller('topLevelFunc');
theCaller('ns.someFunc');
The first call works while the second call shows the callbackFunction type as undefined
Probably a simple syntax issue, but my googling has failed me.
Related
var App = {
method : function (value, callback) {
console.log(value);
if (typeof callback === 'function') {
//here
callback.call( this );
}
}
}
App.method('Hey there', function(){
console.log('callback was executed!');
});
Why do I can't do callback(), but have to call(this) for the callback?
To put it simply, you don't have to. Unless you want your callback function to have its context be the "App" object. For example:
// Regular callback:
var App = {
method : function (value, callback) {
if (typeof callback === 'function') {
callback();
}
}
}
App.method('Hey there', function(){
console.log(
'A regular callback was executed!',
'And its context is Window:',
this === window
);
});
// Context modified callback:
var App = {
method : function (value, callback) {
if (typeof callback === 'function') {
callback.call( this );
}
}
}
App.method('Hey there', function(){
console.log(
'A context modified callback was executed!',
'And its context is App:',
this === App
);
});
I hope that helps!
In the specific case of the callback function you're supplying, it would not matter if you invoked the callback simply with:
callback();
Your callback code does not refer to this at all, so it makes no difference what value it has.
If, however, the callback wanted to refer to other parts of the App object, then invoking with callback.call(this) would ensure that this refers to App in the callback. Example:
var App = {
method : function (value, callback) {
console.log(value);
if (typeof callback === 'function') {
//here
callback.call( this );
}
},
property: "HELLO WORLD"
}
App.method('Hey there', function(){
console.log('callback was executed! Property value is: ' + this.property);
});
With that code, this would have to refer to App in order for the console.log() call to access the object property. The use of .call() ensures that.
Is it possible to pass a callback function that does not exist yet? My goal is to have a common function that will wait for another callback function to exist, when it does exist, it should execute it. This is what I have so far, but I can't figure out how to pass the function in that doesn't exist as a function yet.
function RunTemplateFunction(callback, userInfo) {
if ($.isFunction(callback)) {
callback(userInfo);
} else {
var myInterval = setInterval(function () {
if ($.isFunction(callback)) {
clearInterval(myInterval);
callback(userInfo);
}
}, 200);
}
}
I run the function like this:
RunTemplateFunction(MyFunctionToRun, GetUserInfo());
I get MyFunctionToRun is undefined for obvious reasons, I also tried the workaround of passing the function as a string and then convert the string to a function using eval(). But that throws the same error. I also thought of using the new function(), but that actually creates a new function.
Any help is appreciated. thank you.
If you call RunTemplateFunction by undefined there is no way we can see, is callback is defined or not, as we don't have reference to anything.
If you can modify the declaration to accept object as below, we can achieve what we want
function RunTemplateFunction(options, userInfo) {
if ($.isFunction(options.callback)) {
console.log('called1',userInfo);
options.callback(userInfo);
} else {
var myInterval = setInterval(function () {
if ($.isFunction(options.callback)) {
console.log('Called dynamically!!');
clearInterval(myInterval);
options.callback(userInfo);
}
}, 200);
}
}
var options = {}
RunTemplateFunction(options,{user:122});
options.callback = function(){
console.log("I'm called!!");
}
This will print
Called dynamically!!
I'm called!!
EDIT:
We can also call callback function in following way without setInterval, it will look different but options.callback variable is replaced by template.callMe function and its instantaneous also.
function TemplateRunner(userInfo){
this.callMe = function(cb){
this.templateFunction(cb);
}
this.templateFunction = function(callback){
callback(userInfo);
}
}
var template = new TemplateRunner({user:100})
template.callMe(function(user){
console.log('call me1',user);
});
template.callMe(function(user){
console.log('call me2',user);
})
This will print
call me1 {user: 100}
call me2 {user: 100}
Is there a possibility to make some delay? I call a function in a while loop. This function calls executeQueryAsync which has to finish before the loop continues. When I use an alert my code works but without it doesn't.
while (listPermsEnumerator.moveNext()) {
enumG = groups.getEnumerator();
var rAssignment = listPermsEnumerator.get_current();
var member = rAssignment.get_member();
var groupCounter = 1;
var name = '';
//alert(''); This alert makes code work
while (enumG.moveNext()) {
var group = enumG.get_current();
var groupname = group.get_title();
//alert(groupname);
if (member.get_title() === groupname) {
name = groupname;
SP.SOD.executeOrDelayUntilScriptLoaded(function(){
retrieveAllUsersInGroup(groupname, groupCounter, groups);
}, key);
}
groupCounter++;
}
roleAssignment = this.listRoleAssignments.getByPrincipalId(member.get_id());
roleBindings = roleAssignment.get_roleDefinitionBindings();
// in checkPermission() another executeQqueryAsync is called
checkPermission(context, roleAssignment, roleBindings, name);
}
...
function checkPermission(context, roleAssignment, roleBindings, name) {
this.name = name;
context.load(roleAssignment);
context.load(roleBindings);
context.executeQueryAsync(Function.createDelegate(this, Bind), Function.createDelegate(this, BindFail));
}
The simplest solution would be to code your methods in a way that reflects the purpose of asynchronous operations. You seem to be trying to work around the ExecuteQueryAsync and trying to "make" it synchronous.
Here is a similar example -- see the 2nd answer: ( https://sharepoint.stackexchange.com/questions/95907/executequeryasync-in-for-loop ) Basically you a) write the callback function inline, and b) you put the loop in the success callback.
(What's great about writing the "success" callback function in line is the success callback function then has access to all the variables in the method. It's a closure).
If you need to loop through an array of asynchronous jobs, you can do something like this:
var reports = [11, 12, 14, 15];
function doTheReport() {
if (reports.length === 0) {
alert('All reports are done now.');
return;
}
var report_Id = reports.pop();
$.ajax({
url: "/DoTheReport",
complete: function () {
doTheReport();
}
});
};
Please help in understanding the below code:
// define our function with the callback argument
function some_function(arg1, arg2, callback) {
// this generates a random number between
// arg1 and arg2
var my_number = Math.ceil(Math.random() * (arg1 - arg2) + arg2);
// then we're done, so we'll call the callback and
// pass our result
callback(my_number);
}
// call the function
some_function(5, 15, function(num) {
// this anonymous function will run when the
// callback is called
console.log("callback called! " + num);
});
In the above code,what is the callback keyword.what is the use of this word.
Even there is no function defined with name callback.
The gap in logic I think you're having a hard time with is anonymous, unnamed functions. Once upon a time, all functions were named. So code was written like this:
function MemberProcessingFunction() {
// etc
}
function AdminProcessingFunction() {
// etc
}
var loginProcessingFunction;
if (usertype == 'BasicMember') {
loginProcessingFunction = MemberProcessingFunction;
}
else if (usertype == 'Admin') {
loginProcessingFunction = AdminProcessingFunction;
}
loginProcessingFunction();
Someone thought "This is dumb. I'm only creating those function names to use them in one place in my code. Let's merge that together."
var loginProcessingFunction;
if (usertype == 'BasicMember') {
loginProcessingFunction = function() {
// etc
};
}
else if (usertype == 'Admin') {
loginProcessingFunction = function() {
// etc
};
}
loginProcessingFunction();
This especially saves a lot of time when you're passing a function to another function as an argument. Often, this is used for "callbacks" - occasions where you want to run certain code, but only after a certain indeterminately-timed function has finished its work.
For your top function, callback is the name of the third argument; it expects this to be a function, and it is provided when the method is called. It's not a language keyword - if you did a "find/replace all" of the word "callback" with "batmanvsuperman", it would still work.
'callback' is a function passed as an argument to the 'some_function' method. It is then called with the 'my_number' argument.
when 'some_function' is actually being called as seen below
// call the function
some_function(5, 15, function(num) {
// this anonymous function will run when the
// callback is called
console.log("callback called! " + num);
});
it receives the whole definition of the third function argument. so basically your 'callback' argument has this value below
function(num) {
// this anonymous function will run when the
// callback is called
console.log("callback called! " + num);
}
To understand better how a function can be passed as an argument to another function, take a look at this answer.
I am learning AngularJS and have copied code this basic code from a tutorial (simplified/pseudo code to only include the parts relevant to this question).
The code works for me, but I am trying to better understand how the argument is being passed the the callback in the success method.
// jobService object
var jobService = {
get : function() {
return $http.get( 'some/api/url' );
}
};
jobService.get().success(function (data) {
$scope.jobs = data;
});
My question is, knowing that "normally" arguments are specifically passed into the functions when invoked i.e.:
function foo(arg1) {
alert(arg1); //alerts Hello!
};
foo('hello!');
How is the data argument being passed into the anonymous callback function?
is it:
Being "injected" by AngularJS?
Does the javascript engine simply use variables on the local scope called data?
does the javascript engine look for a data property on the parent object if the success method?
TL;DR
We're just defining that anonymous function, not calling it!
Thus data is a function parameter, not a function argument.
Long version
Let's take this into little pieces.
success() is a function. It's chain-called after jobService.get(). So, whatever the jobService.get() call returns, we're calling the success function of that object (say returnedObject.success()).
Back to success() itself. It can easily read other properties of its object (returnObject from the example above). Since we're passing in the anonymous callback function as an argument, success can easily do something like (narrowing it down to basic JS):
function success(callback) {
var whatever = "I'm passing this to the callback function";
callback(whatever);
}
which would actually call our anonymous function we passed in, and assign it whatever as data (don't forget we're just defining that anonymous function, not calling it!) . This makes data a function parameter, and it is basically a custom name that you use to represent and access what the success function passes into its callback function. You can use whatever you want there - this would still work perfectly fine:
jobService.get().success(function (somethingElse) {
$scope.jobs = somethingElse;
});
Hope I didn't make this too complicated. I was trying to explain it step-by-step from the plain JS standpoint because you can easily read Angular's source to see what it does, so I thought you needed this simpler explanation.
Here's a basic example replicating what's going on there (inspect the JS source, see how the output is the same in all three cases):
var debug = document.getElementById('debug');
function success(callback) {
var whatever = 'hello world';
debug.innerHTML += '<br>success function called, setting parameter to <span>' + whatever + '</span><br>';
callback(whatever);
}
function callbackFunction(someParameter) {
debug.innerHTML += '<br>callbackFunction called with parameter <span>' + someParameter + '</span><br>';
}
success(callbackFunction);
// anon function
success(function(val) {
debug.innerHTML += '<br>anonymous callback function called with parameter <span>' + val + '</span><br>';
})
// anon function 2
success(function(anotherVal) {
debug.innerHTML += '<br>second anonymous callback function called with parameter <span>' + anotherVal + '</span><br>';
})
span {
color: green;
}
<div id="debug"></div>
An example using an object, similar to what is done in your original code:
var debug = document.getElementById('debug');
var myObject = {
whatever: 'hello world',
success: function(callback) {
debug.innerHTML += '<br>success function called, fetching object property and setting the parameter to <span>' + this.whatever + '</span><br>';
callback(this.whatever);
},
modifyMe: function() {
debug.innerHTML += '<br>object property modified<br>';
this.whatever = 'another world';
return this; // this is crucial for chaining
}
}
// anon function callback
myObject.success(function(val) {
debug.innerHTML += '<br>anonymous callback function called with parameter <span>' + val + '</span><br>';
})
debug.innerHTML += '<br><hr>';
// chaining - calling a success function on a modified object
myObject.modifyMe().success(function(val) {
debug.innerHTML += '<br>anonymous callback function called with modified parameter <span>' + val + '</span><br>';
})
span {
color: green;
}
<div id="debug"></div>
Here's the relevant part in the source code:
promise.success = function(fn) {
promise.then(function(response) {
fn(response.data, response.status, response.headers, config);
});
return promise;
};
Read more on GITHUB.