Triggering a function that lives inside jQuery $(document).ready outside of it? - javascript

Been googling and looking for an answer to this / best practice.
Let's say you have most of your javascript inside $(document).ready() for whatever reason, and inside there you have a function that you want to "fire" based on some external javascript function..
What would be the best way to do that? Simply moving the function to the global space isn't entirely a feasible option due to all the variables and stuff inside $(document).ready()
So in this example, there's external javascript that does an ajax request, so when the request is completed, data get's loaded on the page, and then I want to somehow be able to fire that function inside $(document).ready() when that external javascript ajax completes, but I can't simply call that function due to it not being in the global space.

you can use a setter to cast there:
let ready = false
const observe = {}
function run(name, ...args) {
if (observe[name]) observe[name](...args)
else {
let fn
Object.defineProperty(observe, name, {
get() {
return fn
},
set(fnL) {
fn = fnL
fnL(...args)
}
})
}
}
function set(name, fn) {
observe[name] = fn
}
$(document).ready(() => {
ready = true
const textEl = $("#text")
function setText(text) {
textEl.text(text)
}
set('setText', setText)
})
run('setText', 'first run')
setTimeout(() => run('setText', 'delayed 2s'), 2000)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="text">no thing</div>
this is quite powerful if you call the function before $().ready has completed it will wait until $().ready runs. and if $().ready is already running it will call the function too
Usage
in $().ready you have to call set('<function name>', <function>) and when you want to call the function run run('<function name>', ...<argumentts> )
or simpler way you remove $().ready and type <script> at the end of <body> it will work

If you do not want to expose a global then you can make an event that the code has to trigger which will inform when it is done.
$(function () {
function myLocalFunction (e, data) {
console.log('called', data);
}
$(document).on("loadedTheStuff", myLocalFunction);
});
window.setTimeout(function () {
$(document).trigger("loadedTheStuff", "Hello!");
}, 300);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Related

A function to execute two functions but only one executes?

I have tried using a function to execute two functions when the page loads using window.onload, the issue I am having is that the function (myFunc) only executes the first function from the top (Func1) but not (Func2), the function looks like this
window.onload = function myFunc(){
return Func1();
return Func2();
}
So how can I execute both of them?
Try this :)
make sure you define Functions before calling them, this is good practice
//Arrow function and remove the return
const Func1 = () => {
console.log('This is Func1');
}
const Func2 = () => {
console.log('This is Func2');
}
window.onload = myFunc = () => {
Func1();
Func2();
}
do not return because after return goes out of function
window.onload = function myFunc(){
Func1();
Func2();
}
Remove the return keywords, and just run the function as is.
Ref: https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onload
window.onload = function() {
Func1();
Func2();
};
No need for return statements and naming the function. It should trigger both functions, if not please make sure the code change is reflected in the source by putting a breakpoint or adding a debugger; inside the function. Also check if both the function body are doing the same action so that you are concluding as second one not executing.
js engine finishes the execution of function on return keyword.
so dont use return keyword to execute both functions

React.js - How to call a method after another method is fully executed

I have two simple functions. I am trying to call two functions in my "handleSearchClick" function when the button has been clicked.
I would like to run "this.props.getNewsDesc()" after "this.props.fetchNewsApiOrg(this.newsSourceName)" has been fully executed.
Here is the code:
handleSearchClick = () => {
this.props.fetchNewsApiOrg(this.newsSourceName);
this.props.getNewsDesc();
}
Could you please tell me the proper way to call a function after another function is fully executed?
Thank you.
You can pass the method as a parameter and call the function from within the fetchNewsApiOrg().
handleSearchClick = () => {
this.props.fetchNewsApiOrg(this.newsSourceName, this.props.getNewsDesc);
}
...
fetchNewsApiOrg(newsSourceName,getNewDesc){
...
getNewDesc();
}
In this method you will have to bind getNewDesc like,
this.getNewDesc = this.getNewDesc.bind(this) in constructor.
Or you can go with promises.
handleSearchClick = () => {
this.props.fetchNewsApiOrg(this.newsSourceName).then(()=>{
this.props.getNewsDesc();
})
Here the fetchNewsApiOrg should return a promise.

Javascript Restart Timer From Within Closure

I'm trying to figure out how I can reset a timer created inside of an immediately invoking function from within the setTimeout closure. Here is my function:
var triggerHeightRecalc = function() {
setTimeout(function() {
if(imagesLoaded()) {
adjustHeight();
} else {
triggerHeightRecalc();
}
}, 100);
}();
In the event that imagesLoaded() returns false, I receive the following error from attempting to call triggerHeightRecalc():
Uncaught TypeError: undefined is not a function
So I'm not sure if the issue is the function is not in the scope, or maybe it just cannot call itself? I've tried passing triggerHeightRecalc as a parameter in the setTimeout closure, but that doesn't seem to work either.
I've also tried this after reading this SO question:
var triggerHeightRecalc = function() {
var that = this;
var callback = function() {
if(imagesLoaded()) {
adjustHeight();
} else {
that.triggerHeightRecalc();
}
};
timeDelay = window.setTimeout(callback, 100);
}();
What am I doing wrong here, or is there a better way? Is this something that should be a setInterval() instead and I clear the interval when images are loaded?
Side Note: I'm calculating the height of a div inside a jQuery plugin, but I need to wait until the images are loaded in order to get the correct height (not sure if that is relevant).
Since you are invoking the function right from the declaration triggerHeightRecalc is getting set to the return of that function call, which is undefined since you in fact do not return anything.
You can do two things
1. Declare then invoke
var triggerHeightRecalc = function() {
setTimeout(function() {
if(imagesLoaded()) {
adjustHeight();
} else {
triggerHeightRecalc();
}
}, 100);
};
triggerHeightRecalc();
2. Wrap the declaration in () and invoke
var triggerHeightRecalc;
(triggerHeightRecalc = function() {
setTimeout(function() {
if(imagesLoaded()) {
adjustHeight();
} else {
triggerHeightRecalc();
}
}, 100);
})();
The second one will create a global variable unless you do the var triggerHeightRecalc; before hand.
Already answered, but I'll put this in.
First of all, if you just want to wait until all images have loaded you can use:
https://github.com/desandro/imagesloaded and then run the above code.
If that's not what you want, and you you just want a function that your setTimeout can run, then you can remove the () at the end of the function.
Here is what's happening in your current code
Your function is missing the opening bracket or similar character !+( (function.
Also your IIFE has no return keyword, and will return undefined to triggerHeightCalc.
If you do want an IIFE then you can either have a private version that is only callable within itself.
(function myModule(){
myModule(); //calls itself
})();
Or a public version that can be called both inside and outside.
var myModule = (function(){
return function myMod(){
myMod();
}
})();
myModule();
Patrick Evans has the right reasons, but there is a neater way to solve it :)
(function triggerHeightRecalc() {
setTimeout(function() {
if(imagesLoaded()) {
adjustHeight();
} else {
triggerHeightRecalc();
}
}, 100);
})();
Here you are give an internal name to the (still) anonymous function. The name is only visible from within the function itself, its not visible in the global scope. Its called a Named function expression.

Make a function run once by redefining

I've found myself using this pattern recently to do initialization that should only ever run once:
function myInit() {
// do some initialization routines
myInit = function () {return;};
}
This way if I had two different methods which required something myInit did, it would ensure that it would only run once. See:
function optionA() { myInit(); doA(); }
function optionB() { myInit(); doB(); }
In the back of my head I feel like I'm missing something and I shouldn't be doing this. Is there any reasons why I shouldn't write code like this?
Is there any reasons why I shouldn't write code like this?
One reason is that the function will only work as you intend in the scope it was defined in. E.g. if you pass the function somewhere else, it won't be affected by your modifications and in the worst case would create an implicit global variable. E.g.
function myInit() {
// do some initialization routines
myInit = function () {return;};
}
function foo(init) {
init();
init();
}
foo(myInit);
The better approach is to encapsulate the whole logic:
var myInit = (function() {
var initialized = false;
return function() {
if (initialized) return;
initialized = true;
// do some initialization routines
};
}());
Now, no matter how, where and when you call myInit, it will do the initialization step only once.
May be you can do something like,
var myInitCalled = false; // Global declaration of flag variable
function myInit() {
// do some initialization routines
myInitCalled = true; // Setting the global variable as true if the method is executed
myInit = function () {return;};
}
Then in your methods, you can probably use:
function optionA()
{
if(!myInitCalled ) // Checking if first time this is called.
{myInit();}
doA();
}
function optionB()
{
if(!myInitCalled )
{myInit();}
doB();
}
This will ensure that myInit is called only once!!

Template method pattern with setTimeout in JavaScript

I have a close function that will close some instance. The class that includes the function allows derived classes to override close. Here, I want to make sure that close always calls dispose even in derived classes. I achieve this by the following.
function close() {
closeCore();
dispose();
}
function closeCore() {
// derived class can override this method.
}
This works fine, but I have one case where I want to perform CSS animation before I dispose the instance. This is what I do.
function close () {
instance.classList.add("fancy-animation-that-takes-800ms");
setTimeout(function () {
dispose();
},800);
}
But as soon as I do this, the template pattern I use cannot be applied. Is there a way to make sure the close function always call dispose in the second example?
You might have close expect an object be returned from closeCore which had parameters like these:
return {timeout: 800, callback: function () {/*....will execute after a timeout..*/}};
or:
return {callback: function () { /*...will be immediately executed...*/}};
or:
return function () { /*...will be immediately executed...*/};
...and then call their timeout for them (if any), and then after your timeout executed their callback, then call dispose for them.
The relevant part of your close code might look like:
function close() {
var ccObj = closeCore();
var ccIsObj = ccObj && typeof ccObj === 'object';
var callback = typeof ccObj === 'function' ? ccObj : (ccIsObj ? ccObj.callback : null);
if (ccIsObj && ccObj.timeout) {
if (!callback) {
throw 'You must implement a callback when supplying a timeout';
}
setTimeout(function () {
callback();
dispose();
}, ccObj.timeout);
}
else {
if (callback) {callback();}
dispose();
}
}
But if you want to allow the user to make arbitrary asynchronous calls of their own (such as Ajax), while you could instead allow the returning of a promise to which you added the dispose call, you wouldn't have a guarantee that the deriver would ensure the promise completed. You could automatically cancel the promise after a certain period of time, but you couldn't magically know when the deriving code was meant to finish unless again you abstracted this.

Categories

Resources