How to pass parameter to queue _and then_ to setTimeout?... confused - javascript

I have two containers, each triggers some function, which has to pass the object reference.
The function has nested queue and setTimeout, and I need to pas an object reference through both of them, to execute it on the right object.
This is what I tried:
var pimg=parent.find('.prod_img'); // This is the object I actually need to pass;
pimg.children('img:last').queue((function(aaa){
return function() {
whatthe= (function (itema) {
return function() {
itema.children('img').each(function(){
alert(itema.attr('id'));
//alert used for debug.
$(this).stop(false,false).animate({opacity:0},400,function(){
});
});
}
})(aaa)
aaa.data('timeout',window.setTimeout("whatthe()", 400));
}
})(pimg)
);
Now what happens is that if I trigger this function on both of my objects quickly, it would alert the same ID, which suggests that it never passes the object reference.
Note, the pimg is the actual object, it is then called aaa in queue reference, and then itema in the setTimeout reference, but they all supossed to point the same object.
Any advices are appreciated. Thanks

Your code is hurting by brain and I don't have your HTML to actually test this, but If I understand your problem correctly, this should work:
var pimg = parent.find('.prod_img'); // This is the object I actually need to pass;
pimg.children('img:last').queue((function(aaa){
return function() {
var whatthe = (function (itema) {
return function() {
itema.children('img').each(function(){
alert(itema.attr('id'));
//alert used for debug.
$(this).stop(false,false).animate({opacity:0},400, function(){});
});
}
})(aaa)
aaa.data('timeout',window.setTimeout(whatthe, 400));
}
})(pimg));

Related

Calling a nested function present inside JQuery declaration

I have a function called "destination" nested in scrip1.js file. If I add this file at the end of webpage using , how can I trigger it at the next step? Here are some contents of script1.js.
script1.js
$.something = function(element, options) {
function start() {
function destination(arg1, arg2..) {
$.notify(some args);
}
}
$("body").on("click", ".notify-btn", function (event) {
event.preventDefault();
destination(some args);
});
someOtherFunction();
start();
}
$.fn.something = function (options) {
return this.each(function () {
if (undefined == $(this).data("something")) {
var plugin = new $.something(this, options);
$(this).data("something", plugin);
}
});
};
I tried this, but is not working. Chrome console is showing error about this function.
<script type="text/javascript" src="script1.js"></script>
<script>
$.fn.something().destination();
</script>
I can not change this script1.js, so any possible way?
There's no specific connection between variables declared during function execution - and how the rest of the world sees the result of execution. So this code:
function start() {
function destination(arg1, arg2..) {
$.notify(some args);
}
}
start();
... lets destination value (remember, functions in JS are first-class citizens) go away when start() completes its execution. That's actually quite convenient if you want to encapsulate some implementation details and hide it from users; this technique (also known as Module pattern) was often used in pre-class world to implement private properties in vanilla JavaScript.
However, all the values returned from a function can be reused. For example, here...
$.something = function(element, options) {
function start() {
function destination(arg1, arg2..) {
$.notify(some args);
}
return {
destination
};
}
return start();
}
... you make destination function a part of object that is returned from start(). Now $.something returns an object, too; that means it can be reused:
var plugin = new $.something(this, options);
// ...
plugin.destination('some', 'args');
If you're afraid changing the return value might hurt someone, you can try to assign value of destination to $.something object itself as its property, like this:
$.something = function(element, options) {
function start() {
function destination(arg1, arg2..) {
$.notify(some args);
}
return destination;
}
// ...
const destination = start();
$.something.destination = destination;
}
The returned value is not modified, yet function is accessible. Still, that's not actually a good workaround; the biggest issue is that any subsequent calls on $.something will rewrite the value of that function, which might be not a good thing if its execution depends on some scoped variables.
While technically there's a way to fetch destination function code by parsing $.something source code, I really doubt it's worth the effort in your case.

Why this "this" behavior?

Hello I am stuck on a case I don't get
here is the code
function car(speed) {
this.speed = speed;
this.accelerate = function() {
this.speed += 1;
}
}
var oldcar = new car(1);
function test(cb){
cb();
}
test(oldcar.accelerate);
console.log(oldcar.speed);
// 1
test(function(){ oldcar.accelerate(); });
console.log(oldcar.speed);
// 2
On the first function call test(), I observe that the this in the oldcar.accelerate method is set to window.
On the second case, the this is correctly set to oldcar.
I don't understand how calling test() with oldcar.accelerate instead of function(){ oldcar.accelerate(); } make such a difference.
Can someone explain the behavior ? thanks !
Because when you pass a method as a callback you are passing only the method, not the object which it belongs to.
When this is used in without any given scope, it defaults to window (or the closest surrounding scope).
A correct way is to pass the entire object, or an anonymous function has has access to the entire object..
function test(cb){
cb();
}
test(function(){ oldcar.accelerate() });

Is there any way to execute a function in a JS Object prior to executing another function that was called? [duplicate]

This question already has answers here:
Adding console.log to every function automatically
(6 answers)
Closed 8 years ago.
I am trying to debug a large amount of JS Code inside a JS Object. There are somewhere around 150 functions inside this JS Object that are called individually through a separate script.
JS Object Example
var OmnitureCall = {
reportA: function() {
/* random actions */
},
reportB: function() {
/* random actions */
}
...
};
Other JS File Calling Object
OmnitureCall.reportA(...);
Somewhere in an external JS file, multiple reportA's are happening when only one is supposed to happen, which is why I would like to debug the main object and see when various report functions are being called and see where the double event is fired. However, the only way I can see doing this so far would to have a main function inside the OmnitureCall object that acts as a "handler" for all calls, and does some basic debugging and then runs the function that was called.
Example of JS Object Handler
var OmnitureCall = {
handler: function(callback) {
console.log('something is called');
if(typeof(callback) === "function") {
callback();
}
},
reportA: function() {
this.handler(function(){
/* random actions */
});
},
reportB: function() {
this.handler(function(){
/* random actions */
});
}
...
};
The downsides:
There are 100+ functions I would have to copy and paste this.handler too and fix up
In a majority of those functions the 'this' keyword is used to reference other functions within that OmnitureCall object, and I am worried the context of that referenced 'this' will be lost if it is all wrapped as a callback function and then called.
So my question to any JS devs, is there a way I can attach a function to this object that will always be called prior to whatever function was actually called (keep in mind I am also trying to document that name of said function that is being called so I can figure out what is being fired twice).
If that is not possible and the handler function idea is the only thing that may work, does anyone know how to retain the context of 'this' referring to the object as a whole if the function is passed as a parameter to handler and then called?
Much thanks..
Proxies are what you're looking for, but they are not widely implemented - thus I wouldn't recommend it just yet. But for future's sake, this is what it'd look like:
// Your original object
var OmnitureCall = {
reportA: function() {
console.log(arguments, 'hello from report A');
},
reportB: function() {
console.log(arguments, 'hello from report B');
}
// ...
};
// Create our proxy
var OmnitureCall = new Proxy(OmnitureCall,
{
// Since we want to see the calls to methods, we'll use get
get: function(proxy, property)
{
// Tell us what we're calling
console.log('calling ' + property);
// Return it if it exists
return proxy[property] || proxy.getItem(property) || undefined;
}
});
// Returns "calling reportA", ["test", "foo"], "hello from report A":
OmnitureCall.reportA('test', 'foo');
// Returns "calling reportB", [["array", "of", "args"]], "hello from report B":
OmnitureCall.reportB(['args', 'is', 'an', 'array']);
While Brett's code should work, you'd need to change all of the calls to the object. E.g. you can't do OmnitureCall.reportA(); anymore. It'd need to be OmnitureCall.handler('reportA'). You may or may not have control over this, or it may prove too difficult to change all of the references.
Using your original handler setup you can indeed pass the this reference using apply or call:
var OmnitureCall = {
handler: function(callback, args) {
if(typeof(callback) === "function") {
callback.apply(this, args);
}
},
reportA: function() {
this.handler(function(){
console.log(this);
});
},
reportB: function() {
this.handler(function(){
console.log(arguments);
}, arguments);
}
// ...
};
// Outputs Object {handler: function, reportA: function, reportB: function}
OmnitureCall.reportA();
// Outputs "test", ["foo", 1]
OmnitureCall.reportB('test', ['foo', 1]);
You can do something like this http://jsfiddle.net/L4Z8U/ and just call the functions with the handler.
window.OmnitureCall = {
handler: function(callback) {
console.log('something is called',typeof(this[callback]));
if(typeof(this[callback]) === "function") {
this[callback]();
}
},
reportA: function() {
console.log('reportA fired');
},
reportB: function() {
console.log('reportB fired');
}
};
Edit: Ive doen this before using "this" in this context with no issues

explain javascript: value assignment fails

var sc = new stuCore();
function stuCore() {
this.readyPages = [];
this.once = true;
var self = this;
// gets called asynchronously
this.doPrepPage = function (page){
if(self.once == true){
// still gets executed every time, assignment fails
self.once = false;
doSomeStuffOnce();
}
};
this.addReadyPage = function (pageid) {
console.log("readypage called");
this.readyPages.push(pageid);
if (!$.inArray(pageid, self.readyPages) != -1) {
this.doPrepPage(pageid);
}
};
}
why does this assignment fail? I thought I knew the basics of js, but I'm stumped by this. And furthermore what would be a possible solution? call a constructor first and set the variable there?
EDIT:
gets called like this in some other script:
sc.addReadyPage(self.id);
The jQuery.inArray function will return the index in the containing array for the given value. Your script pushes pageid into this.readyPages before checking whether it exists in self.readyPages. this.readyPages and self.readyPages are the same array reference, so the result will always be zero or greater, so the condition that calls doPrepPage will never run.
You could try switching their order around:
this.addReadyPage = function (pageid) {
console.log("readypage called");
if ($.inArray(pageid, self.readyPages) != -1) {
this.readyPages.push(pageid);
this.doPrepPage(pageid);
}
};
(edit: Removed the additional !, thanks #chumkiu)
If I understand correctly you're calling this.doPrepPage as <insert variable name here>.doPrepPage?
If this is the case then your var self passes through to the anonymous function and is stored there, so everytime you call this.doPrepPage it takes the local variable of self.
Try setting self to a global variable, this way it will permanently modify self so each time this.doPrepPage is called it uses the updated variable.

Calling nested function from nested setInterval in an Object Namespace environment

I have this following piece of code:
var stats = {
....,
checkExistance :
function(url){
var newUrl = url.substring(0, url.lastIndexOf("/")) + "/asyncCheckChartExistance";
var xhrObj = stats.getXhr();
var poolInterval = setInterval("poll()", 100);
function poll(){
xhrObj.open("GET", newUrl, true);
xhrObj.send(null);
xhrObj.onreadystatechange = function(){
if(xhrObj.readyState === 4 && xhrObj.status === 200){
if (xhrObj.responseText.length === true){
console.log("Exists!");
clearInterval(poolInterval);
} else {
console.log("Not Yet!");
}
}
}
}
},
}
I created the stats namespace. In this namespace I'm trying to create a function which polls the server every second. I should access this function this way: stats.checkExistance(myUrl).
However it seems that the setInterval function is not able to see the poll() function. I know that this is normal behavior taking in consideration that these are nested inside another function.
If I were to write this in the Global namespace there would be no problem but I'm interested to make this work in this kind of namespace. Any ideas? Thanks!
when you pass a string to setInterval, it runs in the global scope, by default, where poll would not be defined since it only exists in the scope of the checkExistance function.
To fix the issue, pass an anonymous function to setInterval instead:
var poolInterval = setInterval(function () {
poll();
}, 100);
Passing an anonymous function is usually the best idea as it allows you to write any javascript expressions/statements for the interval instead of just calling one function.
When you pass a string to setInterval, that string is interpreted as global code, and since poll is not a global function, a reference error is thrown.
However, you can pass a function reference instead of a string, and since the poll function is available in the scope in which the setInterval invocation is made, you can just write this:
var poolInterval = setInterval( poll, 100 );
var stat = {
say: function(name){
function doit(){
console.log(name);
}
setInterval(doit, 1000);
}
};
stat.say("hi");​​​​​​​​​​​
A simple demo to show how. You will see "hi" every second.

Categories