I basically have been making a program that will go through a website and grab certain images. This is not too hard, just a little complex. I was running the JS code below to click onto the correct page, check for the gallery element to load every 100ms, then finally log the entire object as a string. Most works, but when getting the console.log(...); I get undefined as the main return, and I get the string afterwards as a secondary. This will not due because my program can only intercept the main logged value, not any secondaries. Below is my code and an example output. Thank you!
Code:
document.getElementById('tlcItem_47871').click();
var checkExist = setInterval(function() {
if ($('.pgFooterThumblist').length) {
clearInterval(checkExist);
var ele = document.getElementsByClassName('pgFooterThumb');
console.log(JSON.stringify(ele));
}
}, 100);
Ex Output:
/*Primary Output(First)*/<- undefined
/*Secondary Output(Second)*/<- {"0":{},"1":{},"2":{},"3":{},"4":{},"5":{},"6":{},"7":{},"8":{},"9":{},"10":{},"11":{},"12":{},"13":{},"14":{},"15":{},"16":{},"17":{},"18":{},"19":{},"20":{},"21":{},"22":{},"23":{},"24":{},"25":{},"26":{},"27":{},"28":{},"29":{},"30":{},"31":{},"32":{},"33":{},"34":{},"35":{},"36":{},"37":{},"38":{},"39":{},"40":{},"41":{},"42":{},"43":{},"44":{},"45":{},"46":{},"47":{},"48":{},"49":{},"50":{},"51":{},"52":{},"53":{},"54":{},"55":{},"56":{},"57":{},"58":{},"59":{},"60":{},"61":{},"62":{},"63":{},"64":{},"65":{},"66":{},"67":{},"68":{},"69":{},"70":{},"71":{},"72":{},"73":{},"74":{},"75":{},"76":{},"77":{},"78":{},"79":{},"80":{},"81":{},"82":{},"83":{},"84":{},"85":{},"86":{},"87":{},"88":{},"89":{},"90":{},"91":{},"92":{},"93":{},"94":{},"95":{},"96":{},"97":{},"98":{},"99":{},"100":{},"101":{},"102":{},"103":{},"104":{},"105":{},"106":{},"107":{},"108":{},"109":{},"110":{},"111":{},"112":{},"113":{},"114":{},"115":{},"116":{},"117":{},"118":{},"119":{},"120":{},"121":{},"122":{},"123":{},"124":{},"125":{},"126":{},"127":{},"128":{},"129":{},"130":{},"131":{},"132":{},"133":{},"134":{},"135":{},"136":{},"137":{},"138":{},"139":{},"140":{},"141":{},"142":{},"143":{},"144":{},"145":{},"146":{},"147":{},"148":{},"149":{},"150":{},"151":{},"152":{},"153":{},"154":{},"155":{},"156":{},"157":{},"158":{},"159":{},"160":{},"161":{},"162":{},"163":{},"164":{},"165":{},"166":{},"167":{},"168":{},"169":{},"170":{},"171":{},"172":{},"173":{},"174":{},"175":{},"176":{},"177":{},"178":{},"179":{},"180":{},"181":{},"182":{},"183":{},"184":{},"185":{},"186":{},"187":{},"188":{},"189":{},"190":{},"191":{},"192":{},"193":{},"194":{},"195":{},"196":{},"197":{},"198":{},"199":{},"200":{},"201":{},"202":{},"203":{},"204":{},"205":{},"206":{},"207":{},"208":{},"209":{},"210":{},"211":{},"212":{},"213":{},"214":{},"215":{},"216":{},"217":{},"218":{},"219":{}}
EDIT: In the workflow that I have I am able to set my JS script in my c++, and then I can run javascript into a loaded webpage. The only issue is that the runJavascript() function will take the first value outputted and use that. No way around it so I need the string to be outputted ASAP.
THIS IS NOT A CORRECT ANSWER. I AM LEAVING IT FOR CONTEXT ONLY.
Assuming that all that is need is to avoid console logging an undefined value, this would suffice:
document.getElementById('tlcItem_47871').click();
var checkExist = setInterval(function() {
if ($('.pgFooterThumblist').length) {
clearInterval(checkExist);
var ele = document.getElementsByClassName('pgFooterThumb');
var loggedOutput = JSON.stringify(ele);
if (loggedOutput) {
console.log(loggedOutput);
}
}
}, 100);
This is assuming that somehow your C code intercepts this console log. Generally in JavaScript if you need a value from a function you need to pass it back to the caller using a return statement, but it seems that perhaps you have a unique case in which this is not required.
Please before posting or commenting ... read and understand that this is inside an application that generates the web page and I cannot create a function I can only edit with will happen inside the onclick
Is it possible to use a "if" function inside an "onclick".
The reason why I have to do this is because this "onclick" is used inside an application that I do not control the code, the only thing I can control is what happens inside the "onclick"
For example:
onclick="document.getElementById('REF_DOC_1_NUMBER').value = '';"
I can write the:
document.getElementById('REF_DOC_1_NUMBER').value = '';
I cannot declare any function in the webpage... cause it's an application that compiles the pages... I can only write what is written in the tag onclick...
But not a function. The page is generated by the application itself so I do not control the header.
What I need, a IF that checks an other ID and to change the value ONLY if the value of the other ID (REF_DOC_1_CHOICE) is NA (not applicable)
Any thoughts?
Yes, you can use any inline statement you want. The onclick event is a function by itself. As you can define one in JS in the header:
document.getElementById('mydiv').onclick = function() {
var a = 2;
if (a > 1) {
// do stuff
}
};
You can also do so inline:
onclick="var a=2;if(a>1){a=3}else{a=-1}"
onclick="a == 12 && b = true || b = false"
Here's a JSFiddle
though it is not a good practice to use inline javascript but you can use an if in onclick
onclick="document.getElementById('REF_DOC_1_NUMBER').value = '';if(condition){dosomething}else{dosomething else}"
You may use ternary operator. Somehow like this:
onclick="document.getElementById('REF_DOC_1_CHOICE') == 'some_value'? (document.getElementById('REF_DOC_1_NUMBER').value = '') : 0"
Define a function like this :
onclick="function(text){
// My stuffs
if(text==='test')
document.getElementById('REF_DOC_1_NUMBER').value = '';
}";
I'm writing modular JavaScript and I have a certain function that does a whole lotta processing, viz. Draw 2 canvases, update a lot of variables and store object references. Now I want to execute another function which uses some of the variables updated above.
Something like this:
Paint canvases - Store image dimensions in variables (and a lot of other stuff)
Use those dimensions to do some math and geometry, update the canvases again! I can't do this math in the first function, as it is a common utility function I use to paint canvas, everywhere in my code.
If I inject a setTimeout in my code for 10 seconds, everything works fine, but without it, the second instruction above does not find the updated variables and hence fails.
Any way to work around this? Meaning, I want to execute the second instruction ONLY after some of the required variables are set. Synchronous execution, I say.
Note: I can't post any code here (or anywhere for that matter) as it is not allowed in my workplace!
For cases like this, I suggest to use jQuery and custom events. Simply post an event when the first function has finished updating the canvas. The second function (and anything else) can listen to these events and do whatever they want.
Pro:
No coupling
Individual parts are easy to test
Extensible
Con:
Needs jQuery or you'll need to extract the event handling code.
You could use getters and setters to watch for you for a given condition.
In the setter you can do some computations, check if some conditions are met
and update if required.
Just to give you an idea :
// updateFunc is the function called whenever a property changes
// and all conditions are met for an update.
// newProp1,2,3 are the new values for prop1,2,3
function MyStorageClass(updateFunc, newProp1, newProp2, newProp3 ) {
this.updateFunc = updateFunc;
this.prop1 = newProp1 ;
this.prop2 = newProp2 ;
this.prop3 = newProp3 ;
}
var MSCProto = MyStorageClass.prototype;
// update is needed if all properties are >0
MSCProto.checkUpdateRequired = function() {
return ( ( this.prop1 > 0 ) && (this.prop2 > 0) && (this.prop3 > 0) )
}
Object.defineProperty(MSCProto, 'prop1', {
get : function() { retrurn this._prop1},
set : function(x) { this._prop1 = x;
// and some other computations if need be
if (this.checkUpdateRequired()) this.updateFunc(); } };
Object.defineProperty(MSCProto, 'prop2', {
get : function() { retrurn this._prop2},
set : function(x) { this._prop2 = x;
// and some other computations if need be
if (this.checkUpdateRequired()) this.updateFunc(); } };
Object.defineProperty(MSCProto, 'prop3', {
get : function() { retrurn this._prop3},
set : function(x) { this._prop3 = x;
// and some other computations if need be
if (this.checkUpdateRequired()) this.updateFunc(); } };
I'm trying to write a function that will dump a recursive tree of window for all browsers. A problem that I immediately realized I was going to have, had to do with infinite objects (window.window.window.window). Just for laughs, I tried it anyways, and I got an error as I expected. Uncaught RangeError: Maximum call stack size exceeded (testing in Chrome)
So the first approach to check against objects that were going to cause this was simply:
if (variable != 'window' && variable != 'top' && variable != 'self' && variable != 'frames')
I'm thinking maybe that would have worked, and I simply missed a couple. It was a good theory, but I still get the maximum stack error. So I decided to type window in Chrome's console, and manually look for all of the [DOMWindow] types, to add to this list. While doing that, I noticed the Infinity: Infinity value, which brought me to my next approach:
if (typeof namespace[variable]['Infinity'] === 'undefined')
I still got the maximum stack error with that, so I did a bit of Google searching, and learned about isFinite, so now I have: (edit: actually I just realized isFinite isn't what I thought it was)
if (isFinite(tree[variable]))
The error finally went away, but the problem with this approach is that all objects in window are returning false for this, so the recursion fails. I realize that some of the approaches probably aren't even cross-browser compatible, but it would be nice if I could get it to at least work in one browser in the mean time.
So how can I check for objects that are going to cause an infinite loop?
Here's my code, just for anyone who might be interested:
(function () {
window.onload = function () {
window.onload = ''; // don't want to get our own code
console.log((function (namespace) {
tree = {};
for (var variable in namespace) {
/* gonna need these later
var variable_typeof = typeof namespace[variable],
variable_object_tostring = Object.prototype.toString(namespace[variable]);
*/
//if (variable != 'window' && variable != 'top' && variable != 'self' && variable != 'frames')
//if (typeof namespace[variable]['Infinity'] === 'undefined')
if (isFinite(tree[variable]))
tree[variable] = arguments.callee(namespace[variable]);
else tree[variable] = 'Infinity';
}
return tree;
})(window)); // Start from root
}
})();
Update:
Here is a working product of what I finally came up with, for anyone interested.
GGG is worthy of mention for his help.
function loop (namespace) {
if (namespace['__infinite_test']) return '[[recursion]]'; // It's infinite
namespace['__infinite_test'] = true; // Note that we've been through this object
var tree = {};
for (var variable in namespace) {
try { // For an issue in Chrome throwing an error
namespace[variable]['__tester'] = null;
delete namespace[variable]['__tester'];
}
catch (e) {
tree[variable] = namespace[variable];
continue;
}
if (namespace.propertyIsEnumerable(variable)) tree[variable] = loop(namespace[variable]);
else tree[variable] = namespace[variable];
}
return tree;
}
console.log(loop(window));
One way to prevent infinite recursion in your problem is to keep track of a list of all objects you have already visited and if you encounter an object you've already visited, you don't recurse into it.
When you encounter an object that is not in your list, you add it to your list and then recurse into it.