I'm having some issues figuring how to call a function that I pass into a hash as part of another object. So, I have this constructor to create the objects:
function CheckField(jquery_id, test) {
this.jquery_obj=$(jquery_id);
this.test=function() {test(this.jquery_obj);};
}
Somewhere else in the code I store these objects with custom test functions for each of them into a hash and iterate through them to set them to be called on an interval:
var fields_to_check = {};
fields_to_check["qt_num_box"] = new CheckField("#qt_num_box", function(qnb){return invalid_quotes(qnb);});
fields_to_check["total_num_lines_box"] = new CheckField("#total_num_lines_box",
function(tnlb) {
return isNaN(tnlb()) || 0 >= tnlb.val();
});
//...
for (var key in fields_to_check) {
unsafeWindow.console.log("Setting interval for "+key);
setInterval(set_textbox_border(fields_to_check[key].test, 10000);
}
I'm getting hung up on how to call the custom test function for each of the CheckField objects that I store into fields_to_check.
How can I call the custom test function for each item in the hash?
You can call the function just like you call any other function:
fields_to_check[key].test();
I figured out that I put 10000 in the wrong place, and the first parameter needs to be a function. The call to setInterval should look like this:
setInterval(function() (set_textbox_border(fields_to_check[key].test)), 10000);
Related
I am using JS with Angular came to the following problem.
I am getting data from a requestService, so a call the request function and then do something with the data in a 'success' function. Inside this function, everything is fine and I get all my results but as soon as a leave the success function, my results are undefined. I read some other questions/answers about similar problems, and tried other things. However I do not really know how to hand this and wanted to ask this explicitly with a code example:
function loadShips() {
var count = 0;
RequestService.getShips(nelat, swlat, nelong, swlong, timestamp)
.success(function(results) {
var groupedShips = results.aisData.aisGroupedByShipType;
_.each(groupedShips, function(groupedShip) {
_.each(groupedShip, function(ship) {
Markers['marker' + count] = createMarker(ship);
count++;
});
});
console.log(Markers, '#1')
return Markers
});
console.log(Markers, '#2');
return Markers;
}
So anyone could maybe tell me, why Markers at the print out of '#1' are defined and at '#2' are undefined.
Assuming the request is being done asynchronously, the call at #2 is happening before the request's success method is being called. This would explain why the object does not exist yet.
One solution would be to pass a call back method into the factory as a parameter, and then call that method after the request success has occurred. That would look something like this:
function loadShips(callBack) {
var count = 0;
RequestService.getShips(nelat, swlat, nelong, swlong, timestamp)
.success(function(results) {
var groupedShips = results.aisData.aisGroupedByShipType;
_.each(groupedShips, function(groupedShip) {
_.each(groupedShip, function(ship) {
Markers['marker' + count] = createMarker(ship);
count++;
});
});
console.log(Markers, "#1");
callBack(Markers);
});
}
Using this method looks like this:
function myCallback(markers){
console.log(markers, "#2");
//assign markers to something
}
loadShips(myCallback);
As Will P pointed out, with asynchronous functions, the inline code after them will execute first, because the success function is still waiting in the event queue.
in addition to that, Markers is being returned from inside a anonymous function which will not return it as the result of loadShips but will return it inside ajax wonderland, never to be seen.
what you will have to do is have a function that receives the data when it is ready and call that function with the data. I'm assuming things happen after the ships load, those things will have to be called after the anonymous function is done creating Markers.
function loadShips() {
var count = 0;
RequestService.getShips(nelat, swlat, nelong, swlong, timestamp)
.success(function(results) {
var groupedShips = results.aisData.aisGroupedByShipType;
_.each(groupedShips, function(groupedShip) {
_.each(groupedShip, function(ship) {
Markers['marker' + count] = createMarker(ship);
count++;
});
});
doFancyWonderfulThingsInTheOcean(Markers);
});
}
I am new to js and I am experimenting with closures. There is something I can't get my head around.
If I write
var uniqueInteger = (function() { // Define and invoke
var counter = 0; // Private state of function below
return function() { return counter++; };
}());
and I repeatedly call the function as uniqueInteger() I obtain 0,1,2,3 and so on. It seems then that counter is not destroyed after the function is called. Where is it stored since it is not a global object?
Now, if I slightly change the code and define uniqueInteger as
var uniqueInteger = (function() { // Define and invoke
var counter = 0; // Private state of function below
return function() { return counter++; };
});
and I repeatedly call uniqueInteger()() the value which I obtain is constantly 0. How is that possible?
Where is it stored since it is not a global object?
In the scope created by the closure.
Now, if I slightly change the code … the value which I obtain is constantly 0. How is that possible?
Because every time you call var counter = 0; in the second chunk of code, you rerun the expression var counter = 0; (you also create a new scope and return a new function which you immediately call because you had ()()).
In the first chunk of code you ran that function once and assigned its return value to uniqueInteger, so the expression that set counter to 0 was only evaluated once.
I have a JavaScript constructor function that I want to use to fetch some data asynchronously via Ajax first, and once that's done, call itself again to manipulate the fetched data. This basically means calling the same instance of the constructor function again, but I can't get it to work. Here is a skeleton of what I'm trying to do:
function ajaxmenu(file){
var filefetched = false
var instance = this // save reference to this instance of ajaxmenu
if (!filefetched){
$.get(file, function( data ){
$(data).appendTo(document.body)
filefetched = true
instance() // how can I call instance again to initialize menu again now that ajax file is loaded?
return
})
}
this.menu = $('#menuid') // uses jQuery
this.menu.css({width: '100px'})
//do something else fancy with $menu
}
var menu = new ajaxmenu('menu.htm')
So basically the logic I want to happen here is, when ajaxmenu() is instantiated, the portion inside ajaxmenu() that fetches some file via Ajax is called, then once that's done, the same instance of ajaxmenu() is called again, but this time with the file in place already for the reminder of the function to parse and manipulate.
How can I do this? What I have now, calling instance() returns an error.
Generally speaking, the answer to your question Can I call an initialized object again is yes! You have many options.
If you insist to use the same function again, then one option would be to
add a second parameter filefetched to ajaxmenu
you do not need the var instance = this;
pass a true when calling the ajaxmenu from itself, to skip the fetching: ajaxmenu(file, true);
Full code:
function ajaxmenu(file, filefetched){
if (!filefetched){
$.get(file, function( data ){
$(data).appendTo(document.body)
ajaxmenu(file, true);
});
}
this.menu = $('#menuid') // uses jQuery
this.menu.css({width: '100px'})
//do something else fancy with $menu
}
var menu = new ajaxmenu('menu.htm', false);
Another option (without a self-call) would be to use the callbacks that jQuery offers with the get function and do your change to the menu in the done event, that is executed once the get function completes. This way you don't need the recursive call:
function ajaxmenu(file){
$.get(file, function( data ){
$(data).appendTo(document.body)
})
.done(function() {
this.menu = $('#menuid') // uses jQuery
this.menu.css({width: '100px'})
//do something else fancy with $menu
});
}
var menu = new ajaxmenu('menu.htm');
This also simplifies the code a lot, because you don't need branches (and/or recursive calls) and it is much more readable and so better maintainable.
Generally on recursive calls: you always need a condition to stop the recursion to prevent an infinite loop. One possibility would be using a parameter that is change on every new recursive call:
function process(data, n)
{
// process data
// iterate again or stop recursion
if (n > 0)
{
process(data, n - 1);
}
// done => n = 0
}
// start
process(data, 5);
Another option would be using a global variable and track it's state, but this generally indicates a bad design and it is not recommended:
// global variable
var n = 5;
function process(data)
{
// process data
// iterate again or stop recursion
if (n > 0)
{
n = n - 1;
process(data);
}
// done => n = 0
}
// start
process(data);
I am trying to figure out how to work with a closure function.
On a click event, I want to determine values of parm1 and parm2 and display them in a div,
then update new values to an table with an SQL statement.
If user clicks repeatedly, I want to throttle (debounce) and only perform SQL update 5 seconds after user stops clicking. However, display of parm1 and parm2 should occur on each click.
I am unsure of how to pass the parms to the SQL process.
(function() {
// create debounced function
var d_process = $.debounce(SQLprocess, 5000);
$('#myButton').click(function() {
// determine parameters
var parm1 = 1 + 1; // edit: added var
$(".div_1").text(parm1);
var parm2 = 2+2; // edit: added var
$(".div_2").text(parm2);
d_process();
});
}());
function SQLprocess(parm1, parm2) {
//perform an SQL update
}
Reference:
http://code.google.com/p/jquery-debounce/
To pass SQLprocess with parameters to the debounce function, change this:
var d_process = $.debounce(SQLprocess, 5000);
to this:
var d_process = $.debounce(function() {SQLprocess(parm1, parm2)}, 5000);
This creates an anonymous function with no parameters that is passed to debounce. But that anonymous function calls SQLprocess with the right parmeters.
Some people ask why you can't do this:
var d_process = $.debounce(SQLprocess(parm1, parm2), 5000);
The answer is because, in the Javavscript language, SQLprocess(parm1, parm2) is a function call. It will execute that function immediately and pass the return value to $.debounce() which is not what you want. $.debounce is expecting a function with no arguments so that's what you have to pass it. The way to get your arguments to SQLprocess is to wrap that in a function that has no arguments. It does not have to be an anonymous function. It could also be like this with a named function if you want:
function myFunctionWrapper() {
SQLprocess(parm1, parm2);
}
var d_process = $.debounce(myFunctionWrapper, 5000);
This question already has answers here:
Semaphore-like queue in javascript?
(4 answers)
Closed 6 years ago.
I have created a Queue class in javascript and I would like to store functions as data in a queue. That way I can build up requests (function calls) and respond to them when I need to (actually executing the function).
Is there any way to store a function as data, somewhat similar to
.setTimeout("doSomething()", 1000);
except it would be
functionQueue.enqueue(doSomething());
Where it would store doSomething() as data so when I retrieve the data from the queue, the function would be executed.
I'm guessing I would have to have doSomething() in quotes -> "doSomething()" and some how make it call the function using a string, anyone know how that could be done?
All functions are actually variables, so it's actually pretty easy to store all your functions in array (by referencing them without the ()):
// Create your functions, in a variety of manners...
// (The second method is preferable, but I show the first for reference.)
function fun1() { alert("Message 1"); };
var fun2 = function() { alert("Message 2"); };
// Create an array and append your functions to them
var funqueue = [];
funqueue.push(fun1);
funqueue.push(fun2);
// Remove and execute the first function on the queue
(funqueue.shift())();
This becomes a bit more complex if you want to pass parameters to your functions, but once you've setup the framework for doing this once it becomes easy every time thereafter. Essentially what you're going to do is create a wrapper function which, when invoked, fires off a predefined function with a particular context and parameter set:
// Function wrapping code.
// fn - reference to function.
// context - what you want "this" to be.
// params - array of parameters to pass to function.
var wrapFunction = function(fn, context, params) {
return function() {
fn.apply(context, params);
};
}
Now that we've got a utility function for wrapping, let's see how it's used to create future invocations of functions:
// Create my function to be wrapped
var sayStuff = function(str) {
alert(str);
}
// Wrap the function. Make sure that the params are an array.
var fun1 = wrapFunction(sayStuff, this, ["Hello, world!"]);
var fun2 = wrapFunction(sayStuff, this, ["Goodbye, cruel world!"]);
// Create an array and append your functions to them
var funqueue = [];
funqueue.push(fun1);
funqueue.push(fun2);
// Remove and execute all items in the array
while (funqueue.length > 0) {
(funqueue.shift())();
}
This code could be improved by allowing the wrapper to either use an array or a series of arguments (but doing so would muddle up the example I'm trying to make).
Canonical answer posted here
Here is a nice Queue class you can use without the use of timeouts:
var Queue = (function(){
function Queue() {};
Queue.prototype.running = false;
Queue.prototype.queue = [];
Queue.prototype.add_function = function(callback) {
var _this = this;
//add callback to the queue
this.queue.push(function(){
var finished = callback();
if(typeof finished === "undefined" || finished) {
// if callback returns `false`, then you have to
// call `next` somewhere in the callback
_this.next();
}
});
if(!this.running) {
// if nothing is running, then start the engines!
this.next();
}
return this; // for chaining fun!
}
Queue.prototype.next = function(){
this.running = false;
//get the first element off the queue
var shift = this.queue.shift();
if(shift) {
this.running = true;
shift();
}
}
return Queue;
})();
It can be used like so:
var queue = new Queue;
queue.add_function(function(){
//start running something
});
queue.add_function(function(){
//start running something 2
});
queue.add_function(function(){
//start running something 3
});
Refer to the function you're storing without the () at the end. doSomething is a variable (that happens to be a function); doSomething() is an instruction to execute the function.
Later on, when you're using the queue, you'll want something like (functionQueue.pop())() -- that is, execute functionQueue.pop, and then execute the return value of that call to pop.
You can also use the .call() method of a function object.
function doSomething() {
alert('doSomething');
}
var funcs = new Array();
funcs['doSomething'] = doSomething;
funcs['doSomething'].call();
In addition, you can also add the function directly to the queue:
funcs['somethingElse'] = function() {
alert('somethingElse');
};
funcs['somethingElse'].call();