I have a function which calls itself recursively on a setTimeout. Problem is it loses its scope along the way.
So this is what I have...
var module = function () {
function init() {
if (notYetReadySoTryAgain) {
setTimeout(this.init,100);
return
}
}
}
The second time through I get an error that init cannot be found (on Window object).
What is the canonical way to deal with maintaining a reference to a module across a setTimeout?
Enclose the scope using self-execution; remove this as well.
var module = function () {
(function init() {
if (notYetReadySoTryAgain) {
setTimeout(init,100);
return
}
})(notYetReadySoTryAgain);
}
Remove this. and it will work.
var module = function () {
function init() {
if (notYetReadySoTryAgain) {
setTimeout(init,100);
return
}
}
}
Using setInterval can also be option for you.
try this:
var module = (function () {
(function init() {
if (notYetReadySoTryAgain) {
setTimeout(init,100);
return
}
})()
})()
Related
I want to do something like this:
var build= (function(){
//my function body
})();
function test(){
//somthing then call build
build() //i want to call build function again in my code
}
How can I do this?
I tried this in angular:
var buildRoot = (() => {
$SubNode.get({
TypeID: vendorAdminService.NodeType.Category
}, function(data: vendorAdminService.IGetNodeParameters) {
$scope.ProductTree = data.TreeNodeModelItem;
$scope.AjaxLoading = false;
}, function(err) {
// alert(err)
})
})();
$mdDialog.show(confirm).then(function() {
$Category.Remove(node.ID)
buildRoot
}, function() {
});
but it does not work.
Anybody can guide me??
You need to return a function in your IIFE.
If you IIF is not trivial and has many functionalities you could also consider using Reveal Module Pattern.
var build = (function() {
var f = function() {
console.log('hello');
};
f();
return f;
})();
function test() {
build();
}
test();
Just use a named function.
Your IIFE needs to return a function, for later calling. But then is no need for an anonymous function.
function build() {
//my function body
}
or
var build = function () {
//my function body
};
var build = (function() {
var init = function() {
// magic code
};
return {
init: init
}
}());
function test() {
build.init()
}
test();
You include all your functionalities inside your build object, and you'll be able to call them as soon as you return them from inside that object. This effectively is called the revealing module pattern
For more information, read this
I see that there are missing semi-colons ";"
$mdDialog.show(confirm).then(function() {
$Category.Remove(node.ID);
buildRoot();
}, function() {
});
I just can't reach the function inside function using only HTML.
How to call setLayout() using only HTML or is it able to call only in Javascript?
<button onclick="customize.setLayout('b.html');">Click Please</button>
Javascript:
function customize() {
function setLayout(text) {
var selectedLayout = text;
layout += selectedLayout;
$.get(layout, function (data) {
$("#layout-grid").html(data);
});
}
}
It isn't possible to call setLayout at all.
Functions defined in other functions are scoped to that function. They can only be called by other code from within that scope.
If you want to to be able to call customize.setLayout then you must first create customize (which can be a function, but doesn't need to be) then you need to make setLayout a property of that object.
customize.setLayout = function setLayout(text) { /* yada yada */ };
Multiple ways to call a function within a function. First of all, the inner function isn't visible to the outside until you explicitly expose it Just one way would be:
function outerobj() {
this.innerfunc = function () { alert("hello world"); }
}
This defines an object but currently has no instance. You need to create one first:
var o = new outerobj();
o.innerfunc();
Another approach:
var outerobj = {
innerfunc : function () { alert("hello world"); }
};
This would define an object outerobj which can be used immediately:
outerobj.innerfunc();
if you insist to do it this way, maybe define setLayout and then call it,
something like this:
<script>
function customize(text, CallSetLayout) {
if (CallSetLayout) {
(function setLayout(text) {
//do something
alert(text);
})(text);
}
}
</script>
<button onclick="customize('sometext',true);">Click Please</button>
then you can decide if you even want to define and call setLayout from outside
Simple answer: You can't call setLayout() with this setup anywhere!
The reason being, setLayout() will not be visible outside of customize() not even from other JavaScript code because it is defined locally inside customize() so it has local scope which is only available inside customize(). Like others have mentioned there are other ways possible... (^__^)
You can return the response of setLayout() by returning it as a method of customize() and use it in your HTML like customize().setLayout('b.html'); e.g.
<button onclick="customize().setLayout('b.html');">Click Please</button>
JavaScript:
function customize() {
var setLayout = function (text) {
var selectedLayout = text;
layout += selectedLayout;
$.get(layout, function (data) {
$("#layout-grid").html(data);
});
};
return {
setLayout: setLayout
};
}
Another Approach
You can also define your main function i.e. customize as Immediately-Invoked Function Expression (IIFE). This way you can omit the parenthesis while calling its method in HTML section.
<button onclick="customize.setLayout('b.html');">Click Please</button>
JavaScript
var customize = (function () {
var setLayout = function (text) {
var selectedLayout = text;
layout += selectedLayout;
$.get(layout, function (data) {
$("#layout-grid").html(data);
});
};
return {
setLayout: setLayout
};
})();
You need to treat it as object and method
<button onclick="customize().setLayout('b.html');">Click Please</button>
Sorry I had to edit this code for more clarification
function customize() {
this.setLayout = function setLayout(text) {
var selectedLayout = text;
layout += selectedLayout;
$.get(layout, function (data) {
$("#layout-grid").html(data);
});
}
return this;
}
I have an AngularJS factory that has multiple functions.
I want to call one of the functions inside the other function as shown below:
.factory("AppStart", function($cordovaSQLite) {
return {
init: function() {
var res = "hello";
console.log("in load start up page");
},
create_table: function() {
AppStart.init();
}
}
});
But I get the following error:
AppStart is not defined.
So how do I call the init() function in the create_table() function? I have tried just calling init(), but it doesn't work either.
To accomplish this, I recommend defining your functions with names, and then creating a service object with properties that refer to them, as I did below:
.factory("AppStart", function($cordovaSQLite) {
function init() {
var res = "hello";
console.log("in load start up page");
}
function create_table() {
init();
}
return {
init: init,
create_table: create_table
};
});
When I start my script I have this:
var my_great_masterpiece = new function ()
{
var self = this;
Then later in my script I have this:
response_xml: function ()
{
if (self.http_request.readyState == 4)
{
if (self.http_request.status == 404 && countXmlUrl <= 3)
{
countXmlUrl++;
self.realXmlUrl = xmlUrl[countXmlUrl];
self.request_xml();
}
if (self.http_request.status == 200)
{
self.xmlDoc = self.http_request.responseXML;
self.storage.setItem('domains_raw_xml', self.http_request.responseText);
self.main.peter_save_data();
self.timervar = setTimeout(function ()
{
// ########### Below line gives the error #############################
self.new_version_show_window();
}, 2000);
}
}
},
new_version_show_window: function ()
{
...
}
the error that I am getting is:
Error: self.new_version_show_window is
not a function
What am I doing wrong?
Thanks!
It is unclear from your code where new_version_show_window is defined. Maybe you could explicitly define it on self:
self.new_version_show_window = function () {
/* ... */
}
instead. Or you could define it in the local namespace and use it directly in the setTimeout call:
self.timervar = setTimeout(function () {
new_version_show_window();
}, 2000);
or simply:
self.timervar = setTimeout(new_version_show_window, 2000);
Because of closure, the variables declared in the outer function is also available in the inner function.
Edit
Thanks for posting the entire code. new_version_show_window is defined on this.main, so you must access it thusly:
self.timervar = setTimeout(function () {
self.main.new_version_show_window();
}, 2000);
It could be that self is a reserved word in JavaScript [1]. This could be causing you some problems so try naming the variable something different to start with.
[1] http://www.quackit.com/javascript/javascript_reserved_words.cfm
This is a problem of scope. new_version_show_window is only in scope in the construct in which is it called ( apparently a jQuery AJAX function of some sort). It will only be available to my_great_masterpiece if you define it outside the limited scope in which it now exists.
var Test = (function() {
return {
useSub: function () {
this.Sub.sayHi();
},
init: function () {
$(document).ready(this.useSub);
}
};
})();
Test.Sub = (function () {
return {
sayHi: function () {
alert('hi');
}
};
})();
Test.useSub(); // works
Test.init(); // explodes
Above I am trying to create a Test namespace and add an object Sub to it. I was doing fine until I tried using the object in jQuery. The error is "Uncaught TypeError: Cannot call method 'sayHi' of undefined". If there is a better way to do this, I am open to it.
Edit:
Obviously this was demo code. In my real application the solution that I went with because I think it is the most clear is this one:
var Namespace (function () {
return {
init: function () {
$(document).ready(function() {
Namespace.onReady();
}
},
onReady: function() {
alert('Now I am back in the Namespace scope. Proceed as planned');
}
};
})();
Edit2: All jQuery callbacks seem to require they are used in this manner or else the scoping is screwed up.
I think it is a scope problem. If you do
$(document).ready(this.useSub);
then this.useSub will be executed in the window scope (so inside the function, this refers to the window object) and there doesn't exist a Sub attribute.
Try:
init: function () {
var obj = this;
$(function(){obj.useSub()});
}
For some reason it does not work using $(document).ready(function(){obj.useSub()}); but it works with the $() shortcut.
Here is one way
var Test = {
useSub : function () {
Test.Sub.sayHi();
},
init: function () {
$(document).ready(Test.useSub);
},
Sub: {
sayHi: function () {
alert('hi');
}
}
};
in this line:
$(document).ready(this.useSub);
you're passing a reference to a function and the scope is lost- when the function runs, this no longer means Test.