call function inside method from external js - javascript

Please bear with me since I am a newbie in JS programming.
I have the following problem:
One of my modules contains a setInterval loop.
This module is called by my server.js when an HTML button is clicked (ON, variable state in the code). I would like to interrupt its execution (OFF) from the server.js but it doesn't work..
I know it feels like a duplicate question, but I have searched a lot for the info inside Stack Overflow and all questions refer to code being executed and stopped from within the same file. In my case, I am calling a method in an external file (which contains the setInterval) and I want to trigger clearInterval which should be ran in that external file!
Simplified code below:
action.js
module.a = function(milisec) {
var myVar = setInterval( function() { do stuff }, milisec);
}
module.exports = methods;
My first attempt:
Server.js
// var state is a button on my HTML
var actions = require('./actions');
If (state == 1)
{ actions.a(milisec) }
If (state == 0)
{ clearInterval(myVar) }
But it didn't work. And I think it's also clear why: The code has no clue where I got the myVar from, basically I think I should call a function from inside the module to stop the setInterval, therefore, I included the function stop() in the method.
My second attempt:
action.js
methods.a = fuction(milisec) {
var myVar = setInterval( function() {
console.log("I'm being executed");}, milisec);
function stop() {
clearInterval(myVar);
}
}
Module.exports = methods;
But I don't know how to refer to the function inside my methods.a on the server.js file
I've tried:
actions.a.stop()
but it doesn't work at all..
Is it even possible? Is there a way to execute the clearInterval in my server.js?
Appreciate your help

You are declaring myVar inside of methods.a(), making it's scope local to that function. Try declaring myVar outside of the function.

Related

Javascript control program flow when you can't modify async function

So all the examples I've seen with promises or callbacks usually involve injecting the callback into the asynchronous function inside of the setTimeout or something like that. But what if you have a function that you can't modify for whatever reason. Maybe it's imported from a library, idk. Imagine this code.
const funcA = () => {
setTimeout(() =>console.log("first"), 500)
}
const funcB = () => {
console.log("second");
}
funcA();
funcB();
How do you get second to print after first, without modifying funcA?
TLDR: Abandon the code.
All async functions in javascript either return a promise or accept a callback. This has been the culture in javascript since the mid 2000s. If you ever encounter the situation in your question the best solution is to not use that library and find something else.
Workaround..
However, there are times when you need to do something like this. For example if you develop a mashup script that can be inserted by the user into his HTML and you have no control how the user copy/paste your code.
One workaround is to use setTimeout or setInterval to monitor something for change. This can be a variable, a <div>, an <input> etc. Here's a silly example that waits for jQuery to load:
const funcB = () => {
console.log("second");
}
function waitForJQuery () {
if (window.jQuery || window.$) { // check if jQuery variable exist
console.log('jQuery loaded');
funcB();
}
else {
setTimeout(waitForJQuery, 200); // check 5 times per second
}
}
waitForJQuery();
Normally you would not write code like this. But IF and only if you have no other choice you can do something like this.
Note though that this requires whatever you are waiting for to generate a side effect: either creating a global variable or modifying a global variable or updating the DOM etc.

Is there a way to call function defined inside onload from an external file

Following is a sample code created based on the scenario. showData() function is defined inside a javascript load function. I wanted to call showData() from another file maybe on a button click. I know this will work if the showData is made global. It's not possible to make the function global, as in this scenario it's a dynamically generated code. Is there anyway in JS that allows to call such functions ?
// Not possible to change the structure of this file as its coming dynamically
window.addEventListener("load", function() {
showData(); // 1st time call
function showData() {
console.log('starting execution')
}
});
// Calling from another file
showData(); // 2nd time call - not possible
No.
The function is declared inside another function. Its scope is that function.
Unless you change that code to make it a global, it isn't accessible from outside the containing function at all.
If the structure of the code can't be changed, perhaps you could try attaching your function to the global window object, like:
window.addEventListener("load", function() {
// attached to window
window.showData = function() {
console.log('starting execution')
};
window.showData(); // 1st time call
});
// Calling from another file
window.showData();
But make sure the second call (from the other file) has a little bit of a delay (remember the eventListener has to be attached to the window first, before the function becomes available).
You could try:
// second call
setTimeout(function() {
window.showData();
}, 1000);

Know every function on scope

I have a function main that has several inner functions like this:
function main_f (params) {
function do_this () {
// do this...
}
function do_that () {
do_this(); // working
main_f.parse_stuff(); // not working
parse_stuff(); // not working
}
do_that();
main_f.parse_stuff = function(){
console.log("success");
}
}
function second_f () {
main_f.parse_stuff(); //working
}
I was expecting that main_f.parse_stuff() would work inside do_that, but that is not the case. My questions are:
-Is it posible to call that method from inside main_f ? how?
EDIT: Execute do_that after parse_stuff is written.
-Why can't I call parse_stuff from main_f?
EDIT: I just realised that the function doesn't read on compilation time, but execution time, therefore it is not visible when do_that is called.
-How can I know every function on scope?
It is not possible by programation but you can do it with the debugger. Just insert a break point on that scope and you can check everything that is global, local and in the closure.
I checked this with chrome dev-tools.

How can I make variables so that I don't have to repeat myself in future functions

WARNING!! I AM A NOVICE THROUGH AND THROUGH
Alright, so I know there have been a lot questions about Global variables, and I think that's what I'm looking for, but, not exactly. Lately I've been needing to call upon the same lines of code several times. document.getElementById("example").style or similar to little things like that but I need to continuously repeat.
My question is how do I make it so that I make one variable, outside of the function, to save time writing these lines?
What I've been seeing is to simply write it outside like this var inferno = document.getElementById("inferno"); but this is far from working.
This is my code right now, it's simple because I was just using it as a test, but can anyone help me?
var inferno = document.getElementById("inferno");
function infernoClick () {
inferno.style.backgroundColor="red";
}
You have the right idea. Note, though, that the variable doesn't have to be global. It just has to be where all of the code that wants to use it can use it.
For example, this creates a global:
<script>
var inferno = document.getElementById("inferno");
function infernoClick () {
inferno.style.backgroundColor="red";
}
function somethingElse () {
inferno.style.color="green";
}
</script>
(Note that this needs to be after the markup creating the inferno element.)
The problem with globals is that they can conflict with each other, and in fact the global "namespace" is really, really crowded already.
You can avoid that by wrapping up the code that needs inferno in a scoping function, like this:
<script>
(function() {
var inferno = document.getElementById("inferno");
function infernoClick () {
inferno.style.backgroundColor="red";
}
function somethingElse () {
inferno.style.color="green";
}
})();
</script>
That code creates an anonymous function and then calls it immediately, running the code inside.
Now inferno is "global" to the functions that need it, but isn't actually a global.
Let's take a further example:
<script>
(function() {
var outer = 42;
function doSomethingCool() {
var inner = 67;
document.getElementById("someElement").onclick = function() {
alert("inner = " + inner + ", outer = " + outer);
};
}
// Can't use `inner` here, but can use `outer`
alert("outer = " + outer);
doSomethingCool();
})();
</script>
That code wraps everything in a scoping function, and the outer variable is accessible everywhere within that scoping function. It also has a function, doSomethingCool, which has a variable called inner. inner is only accessible within doSomethingCool. Look at what doSomethingCool does: It hooks up an event handler for when someElement is clicked. It doesn't call the function, it just hooks it up.
The really cool thing is that later, when someone clicks the element, that function has access to that inner variable.
And in fact, that's true for arguments you pass into the function as well. One last example:
<input type="button" id="element1" value="One">
<input type="button" id="element2" value="Two">
<script>
(function() {
function hookItUp(id, msg) {
document.getElementById(id).onclick = function() {
alert(msg);
};
}
hookItUp("element1", "This message is for element1");
hookItUp("element2", "And this one is for element2");
})();
</script>
There, we have this function that accepts a couple of arguments, and we call it twice: Once to hook up click on element1, and again to hook up click on element2.
The really cool thing here is that even though the clicks happen much later, after the calls to hookItUp have long-since returned, the functions created when we called hookItUp still have access to the arguments we passed to it — when we click element1, we get "This message is for element1", and when we click element2, we get "And this one is for element2."
These are called closures. You can read more about them on my blog: Closures are not complicated
That'll work, but only if the declaration appears after the point in the DOM where the element actually appears. Try moving your <script> to the very end of the <body>.
Another thing you can do is use the window "load" event to make sure the whole DOM has been seen before your code runs.
for example
var myGlobalVars = {"inferno":null,"othervar":null}; // globals in their own scope
function clickMe(varName,color) { // generic function
myGlobalVars[varName].style.backgroundColor=color;
}
window.onload=function() {
// initialise after the objects are available
for (var o in myGlobalVars) myGlobalVars[o]=document.getElementById(o);
// execute
clickMe("inferno","red");
}
.
.
T.J. Crowder gave a beautiful answer about scoping; just to add on that you can also use an immediately-invoked function expression to create a module with your UI elements, i.e.
var UI = (function() {
...
return {
inferno: document.getElementById("inferno");
};
})();
...
UI.inferno.style = ...;

window.setInterval from inside an object

I'm currently having an issue where I have a javascript object that is trying to use setInterval to call a private function inside of itself. However, it can't find the object when I try to call it. I have a feeling that it's because window.setInterval is trying to call into the object from outside but doesn't have a reference to the object. FWIW - I can't get it to work with the function being public either.
The basic requirement is that I may need to have multiple instances of this object to track multiple uploads that are occurring at once. If you have a better design than the current one or can get the current one working then I'm all ears.
The following code is meant to continuously ping a web service to get the status of my file upload:
var FileUploader = function(uploadKey) {
var intervalId;
var UpdateProgress = function() {
$.get('someWebService', {},
function(json) {
alert('success');
});
};
return {
BeginTrackProgress: function() {
intervalId = window.setInterval('UpdateProgress()', 1500);
},
EndTrackProgress: function() {
clearInterval(intervalId);
}
};
};
This is how it is being called:
var fileUploader = new FileUploader('myFileKey');
fileUploader.BeginTrackProgress();
Use this
intervalId = window.setInterval(UpdateProgress, 1500);
setInterval with a literal argument will eval this in the global scope where UpdateProgress is not accessible.
Because it is an eval expression, it does not have access to the scope that setInterval is created in. Try:
intervalId = window.setInterval(UpdateProgress, 1500)
It is generally good practice to avoid eval style expressions wherever possible. For instance, if you wanted to call several functions from the same timer, you would use an anonymous function instead of a string.
window.setInterval(function () {
function1();
function2();
}, 1500)
See also
Why is using javascript eval() a bad idea?
Anonymous function - Wikipedia
+1 to Andy E's head (I can't upvote yet, doh!)
Another gotcha that could get you is if you use this from within the called function.
Then doing exactly what Andy has with this addition should get you by.
var that = this;
window.setInterval(function() {
function1.apply(that);
function2.apply(that);
}, 1500);

Categories