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);
Related
if (msg.content.toLowerCase() === "!start") {
var gov = setInterval(go, 1000);
var onev = setInterval(one, 1000);
var twov = setInterval(two, 1000);
function two(msg) {
msg.channel.send("https://i.imgur.com/JZOCg5l.png ");
}
function one(msg) {
msg.channel.send("https://i.imgur.com/gTK3Vhn.png ");
}
function go(msg) {
msg.channel.send("https://i.imgur.com/3iVfYIR.png ");
}
function two(msg) { }
function one(msg) { }
function go(msg) { }
msg.channel.sendFile("https://i.imgur.com/kOoyoZQ.png ").then(onev).then(twov).then(gov);
}
This is a very annoying task. I need to send these images about one second appart.
The current framework keeps giving me the following error:
C:\Users\maver\Documents\TestBot\testlev.js:197
msg.channel.sendFile("https://i.imgur.com/3iVfYIR.png ");
^
TypeError: Cannot read property 'channel' of undefined at Timeout.three [as _onTimeout]
(C:\Users\maver\Documents\TestBot\testlev.js:197:17)
at ontimeout (timers.js:478:11)
at tryOnTimeout (timers.js:302:5)
at Timer.listOnTimeout (timers.js:262:5)
I've tried this a multitude of different ways and am just about ready to throw in the towel.
Your syntax is slightly off. When you do function two(msg){... you are actually telling the function that you are going to pass it a new variable and that you want that variable called msg. Because of that, msg (in the context of your function) is undefined. You would have to pass in msg when you call the function from setInterval().
There are 2 ways you can bind msg to your function. The way that I personally like is this:
//...
var gov = setInterval(go.bind(null, msg), 1000);
var onev = setInterval(one.bind(null, msg), 1000);
var twov = setInterval(two.bind(null, msg), 1000);
//...
The .bind() function assigns the value of arguments. With the first argument of the function being called being the second argument of bind(). The first argument of bind() is what should be used as the value of this inside the function.
The other way to do this is with an anonymous function
//...
var gov = setInterval(function(){go(msg)}, 1000);
var onev = setInterval(function(){one(msg)}, 1000);
var twov = setInterval(function(){two(msg)}, 1000);
//...
Also note, setInterval() repeats a function call ever period. You may be looking for setTimeout() which would only fire the functions once after a delay.
When you use setInterval, you should know it will call the function, but will not provide any parameters to it (or even this). One way to fix it would be by using bind:
setInterval(go.bind(null, msg), 1000)
This would work, because bind() will create a new function where the parameters are "magically set in advance".
Another option in this case would be to simply not re-declare msg in the three functions - in that case, javascript will try to find msg from the outer scope, where it exists:
function two() {
msg.channel.send("https://i.imgur.com/JZOCg5l.png ");
}
Third, you shouldn't be using setInterval, but setTimeout, which will only call the function once.
The fourth problem you have is with timing. First, all three setTimeout calls happen at the same time, so all three functions will be called in one second (after 1000 millis). An easy fix would be simply:
setTimeout(go, 1000);
setTimeout(one, 2000);
setTimeout(two, 3000);
However, that will completely ignore how long it takes to send each message (which may or may not be what you want). If you wanted to wait a second after the previous message is sent, then you'd have to do something like:
msg.channel.sendFile("https://i.imgur.com/kOoyoZQ.png ").then(function() {
setTimeout(go, 1000);
});
function go() {
msg.channel.send("https://i.imgur.com/3iVfYIR.png").then(function() {
setTimeout(one, 1000);
});
}
// etc
That would be very tedious, as all the functions will look very similar. So a better approach would be to create a list of messages, then have a single function to send all of them:
var msgs = [
"https://i.imgur.com/kOoyoZQ.png",
"https://i.imgur.com/JZOCg5l.png",
"https://i.imgur.com/gTK3Vhn.png",
"https://i.imgur.com/3iVfYIR.png"
];
function sendMsgs(msgs, delay) {
if (msgs.length < 1) return; // we're done
var remain = msgs.slice(1);
var sendRemain = sendMsgs.bind(null, remain, delay);
msg.channel.send(msgs[0]).then(function() {
setTimeout(sendRemain, delay);
});
}
sendMsgs(msgs, 1000);
Your code is executed immediately because you have to maintain the value anf promises you are using is not correctly used.
You can do it as follows :
if (msg.content.toLowerCase() === "!start") {
var urls = ["https://i.imgur.com/kOoyoZQ.png",
"https://i.imgur.com/JZOCg5l.png",
"https://i.imgur.com/gTK3Vhn.png",
"https://i.imgur.com/3iVfYIR.png" ];
function gov(urls){
for(let k=0; k<urls.length;k++){
setTimeout(function() { msg.channel.send(k); },k*1000)
}
}
gov(urls);
}
I have this piece of JavaScript code, and I want it to be able to use calculate() in the second function (which does work), but the problem is that the first function uses a variable declared in the second function. Also, I need var first=prompt to be executed only when chemicalcalc is invoked.
function calculate(){
var calctrans=parseInt(firsttrans, 10)
return calctrans;
}
function chemicalcalc(){
var first=prompt("Enter first term\nLeave bank to go back to element finder");
if(first==""){
calculate();
}else{
var firsttrans=first.replace("h", 1);
}
}
chemicalcalc();
By nesting the calculate() inside of chemicalcalc, you allow calculate to have access to the parent function's scope.
However, if the user doesn't enter anything and just hits ENTER at the prompt, your code will invoke calculate, which will then attempt to use firsttrans, which won't have a value because the branch of the if that sets the value isn't entered, so you have a logic error there.
I have removed that if/then logic to show how the rest of the function would work.
function chemicalcalc(){
var first = prompt("Enter first term\nLeave bank to go back to element finder");
var firsttrans = first.replace("h", 1);
// Invoke calculate and return whatever it returns
return calculate();
// Nested functions always have access to the parent's scope
function calculate(){
var calctrans = parseInt(firsttrans, 10)
return calctrans;
}
}
console.log(chemicalcalc());
Another option (instead of nesting functions) is to simply pass the second function the data it requires as an argument:
function chemicalcalc(){
var first = prompt("Enter first term\nLeave bank to go back to element finder");
var firsttrans = first.replace("h", 1);
// Invoke calculate and pass it the data it needs, then return whatever it returns
return calculate(firsttrans);
}
// Now the function expects data to be passed by the caller
function calculate(data){
var calctrans = parseInt(data, 10)
return calctrans;
}
console.log(chemicalcalc());
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);
I wonder why, as soon as the page loads, the function btw_bijtellen () is called. I wanted to call it by clicking...
var $ = function (id) {
return document.getElementById (id);
}
function btw_bijtellen () {
window.alert("we want to calculate something after clicking th button");
}
$("bereken").onclick = btw_bijtellen ();
You've added () which causes the function to execute.
For example:
var myFunc1 = function() {
alert('Hello');
}(); // <--- () causes self execution
var myFunc2 = function() {
return 5 + 5;
};
var some_value = myFunc2(); // <--- Again () causes execution (you'd expect this one)
In your case, as mentioned in comments you're basically telling the onclick to set its value to the return value of the function.
If you drop the () it should run as expected.
If you want the function to be called on click then use
$("bereken").on('click', btw_bijtellen);
Update (As per query from WAO)
If you need to pass the argument, then you need to specify as the second argument. the $.on() gets the data in the event handler
$("bereken").on('click', {key1: value1, key2: value2, keyn: valuen}, btw_bijtellen);
where, you can get your parameters from event.data
var function = btw_bijtellen(event) {
var data = event.data;
console.log(data);
var key1 = event.data.key1;
console.log(key1); // this will output value1
}
Have a read on this link jQuery $.on() api
Putting () after a function name is how you call it.
If you want to assign the btw_bijtellen to onclick then remove the () from the last line of the code in the question.
With the () there, you are calling the function and assigning its return value to onclick. Since that function has no return statement, that value will be undefined which is not what you want.
I need to run a function on my node.js server, that completes the same task every 15 minutes.
I Used for that setInterval as in example number 3 here - http://tinyurl.com/c2jj7dl.
So, I got to something like this:
exports.start = function (list, callback){
setInterval(stuffTop.loadstuff, 900000, list, function (parsedList) {
// CODE STUFF HERE
// THEN THE CALLBACK.
callback(parsedDynamicList);
});
}
Actually this stuff work, but the function gets completed for the first time - only after 900000MS.
Is there an option to make to function complete (in the first round) - straight when called ? Thanks.
Use a function which recursivly calls itself:
foo = function(){
doStuff()
setTimeout(foo,900000)
}
In your case It would look like this:
exports.start = function (list, callback){
var foo = function () {
stuffTop.loadstuff(list, function(parsedList) {
//CODE STUFF HERE
//THEN THE CALLBACK
callback(parsedDynamicList);
setTimeout(foo,900000);
});
}
foo();
}
The solution to your question is simple. Call the function before going into the setInterval. Like this:
var callback=function(){}
var list=['some','list'];
var repeaterFunction = function(){console.log("do now!")}
var start = function (list, callback){
repeaterFunction();
var repeater = setInterval(repeaterFunction, 5000, list, function(parsedList){
// CODE STUFF HERE
// THEN THE CALLBACK.
callback(parsedDynamicList);
});
}
start()
The fact that I use var repeater = setInterval(... allows for the clearInterval(repeater) whenever you wish.
Here's the fiddle