Javascript associative array not working on Jquery objects - javascript

I am trying to build a associative array parentTds however it's not working the way I would like.
var parentTds = {};
var index = 0;
$.each(clone, function () {
var $currentItem = $(selectedActivities[index]);
var $currentItemTd = $currentItem.closest('td');
console.log($currentItemTd.get(0));
var borderLeft = 0;
console.log(parentTds[$currentItemTd.get(0)]);
console.log(parentTds[$currentItemTd]);
if (typeof parentTds[$currentItemTd.get(0)] === "undefined") {
console.log('NOT OK');
borderLeft++;
parentTds[$currentItemTd.get(0)] = $currentItemTd;
} else {
console.log('OK');
}
index++;
});
For some reason parentTds[$currentItemTd.get(0)] always returns the 1st item stored. I get NOT OK just the 1st time the loop runs whereas I should be getting NOT OK a few more times. I suspect the problem is parentTds[$currentItemTd.get(0)] itself.
Any ideas please?

Javascript is not as forgiving as for example PHP. When you use this:
if (typeof parentTds[$currentItemTd.get(0)] === "undefined") {
$currentItemTd.get(0) might be evaulated as 0 and therefore the reference is always parentTds[0]
In these circumstance I use to break up the code-block and do something like this:
var cig = $currentItemTd.get(0);
if (typeof parentTds[cig] === "undefined") {

Related

JavaScript loop through all existing objects to find an object key

I am trying to debug a system that was built by someone else. I have a minified library that makes an ajax (xhr) call to an external data source and writes the received data to an object or a variable. The call is made immediately after page load so I can't catch it by appending a function to register all XHR call requests. So I am trying to run a loop through all variables and objects that the browser window has. I am trying this:
var foundVar = false;
loopThroughObject(this);
function loopThroughObject(obj) {
if (!foundVar) {
try {
for (var name in obj) {
if (obj[name] && {}.toString.call(obj[name]) === '[object Function]') { //making sure that the object is not a function
} else {
if (name == 'searchedKey') { //found the object with key = searchedKey
console.log(obj[name]);
foundVar = true;
} else {
setTimeout(loopThroughObject.bind(null, obj[name]), 10); //do more recursion of inner objects
}
}
}
} catch (error) {}
}
}
The problem is that the setTimeout(loopThroughObject.bind(null, obj[name]), 0); part stacks up and a memory issue occurs. I tried the simple loopThroughObject(obj[name]), but I am facing the "Too much recursion" error after 25000 loops. It also seems that I am missing something and it causes the loop go through some object types that I don't need. Does anyone know a more efficient way to do that loop?
P.S. I tried a very simple HTML page and the code works fine:
<html>
<head>
<script>
var test = JSON.parse("{\"searchedKey\":\"12\"}");
</script>
</head>
<body>
</body>
</html>
The problem is almost certainly the fact that window has several properties that point back to itself, so your code is going into an infinite loop. There may well be other circular references.
You can remember what objects you've already looked in using a Set, like this (I've also added a few other tweaks; for instance, you can check for a function with typeof x === "function"):
let foundVar = false;
let seen = new Set();
loopThroughObject(this);
function loopThroughObject(obj) {
if (!foundVar) {
try {
for (const name in obj) {
const value = obj[name];
if (typeof value !== "function") {
if (name == "searchedKey") { // found the object with key = searchedKey
console.log(value);
foundVar = true;
break;
} else if (value && typeof value === "object" && !seen.has(value)) {
seen.add(value);
loopThroughObject(value); // No need for setTimeout
}
}
}
} catch (error) {}
}
}

Iterate a function until result from called function is equal, javascript

I need to iterate a function several times until it returns same thing twice.
This needs to go into a for-loop somehow but I can't get my head around how to this. Here's some code with 4 manual iterations. Any ideas how to put this in a for-loop?
Velocity.prototype.removeCombinedDistancesThatAreShorterThanTrainLength = function(wayPoints, lengthOfTrain){
var firstTry = this.removeWayPointsWhichAreShorterThenTrainLength(wayPoints, lengthOfTrain);
var secondTry = this.removeWayPointsWhichAreShorterThenTrainLength(firstTry, lengthOfTrain);
if(firstTry === secondTry){
return firstTry;
}else{
var thirdTry = this.removeWayPointsWhichAreShorterThenTrainLength(secondTry, lengthOfTrain);
if(thirdTry === secondTry){
return secondTry
}else{
var forthTry = this.removeWayPointsWhichAreShorterThenTrainLength(thirdTry, lengthOfTrain);
if(thirdTry === forthTry){
return forthTry
}
}
}
return forthTry;
};
Something like this (not tried, but should give you the general idea):
var lastTry = null;
var thisTry = wayPoints;
do
{
lastTry = thisTry;
thisTry = this.removeWayPointsWhichAreShorterThenTrainLength(lastTry, lengthOfTrain);
} while (lastTry !== thisTry);
If it's possible that the result will never become equal, consider implementing a safeguard for this, like a maximum number of iterations.

Get value if all objects in chain exist, get fallback value if not

Feel kind of stupid to ask..
I want to get something like this:
var value = $scope.settings.paper.font.color || 0;
The problem is that some of the middle objects may not exist.
Is there an ultimate way to get value if all "object chain" exists and get some fallback if not?
For example, in line above if all objects exists, we may return value of color, but if only $scope.settings exists, and there's no paper object in it, i will get an error, not 0.
First of all: There is no builtin function for it.
Shortest generic solution
Simply wrap it into a try - catch
try {
// handles defaultVal if d is undefined
yourVar = typeof a.b.c.d === 'undefined' ? defaultVal:a.b.c.d;
} catch (e) {
// handles defaultVal if a,b or c are undefined
yourVar = defaultVal;
}
Alternative solution
You could use the following function to safely traverse an object (gv - for getValue):
var gv = function(scope, chainStr, defaultValue) {
var chain = chainStr.split('.');
for (var i = 0; i < chain.length; i++) {
var newScope = scope[chain[i]];
if (typeof newScope !== 'undefined') {
scope = newScope;
} else {
return defaultValue;
}
};
return newScope;
};
Like this:
var a = {b:{c:{d:3}}};
console.log(gv(window, 'a.b.c.d', -1));
// 3
console.log(gv(window, 'a.b.c.e', -1));
// -1
console.log(gv(a, 'b.c.d', -1));
// 3
console.log(gv(a, 'b.c.e', -1));
// -1
Sure, just check for the existence of $scope and each property in its namespace:
var value = (typeof $scope != 'undefined' && $scope.settings && $scope.settings.paper && $scope.settings.paper.font && $scope.settings.paper.font.color) || 0;
The last part of the statement in parenthesis will return the value of .font
Example: http://jsfiddle.net/silkster/gM8uh/
You can also make use of build in $parse service:
var value = $parse('settings.paper.font.color || 0')($scope);
It will make all necessary checks behind the scene.
Demo: http://plnkr.co/edit/1GLb5PEvxMzPMYc5ZxZn?p=preview

Set JavaScript variable to check definition later

How can you set a var to something you want to later check if it's defined or not?
Example: To check if jQuery is not defined, you'd do this:
if (typeof(jQuery) === 'undefined') {
}
But what if I want to do something like this (this obviously doesn't work):
var toCheckLater = jQuery; // This fails.
// Some time later..
if (typeof(toCheckLater) === 'undefined') {
}
What I'm trying to do is dynamically load scripts from an array, but I want to set ahead of time the variable whose definition I'll check for later. And I'd like to avoid a big block of ifs or switch statement. Meaning I'm hoping to find a solution a bit more elegant than:
switch (scriptName) {
case 'jQuery':
if (typeof(jQuery) === 'undefined') {
}
break;
case 'someOtherScriptName':
.
.
.
}
Any ideas?
Thanks in advance.
A function would do:
var toCheckLater = function() { return typeof jQuery == "undefined"; }
// later:
toCheckLater()
You might also use a fabric for such functions:
function getChecker(name) {
return function() {
return typeof window[name] == "undefined";
// alternative:
return name in window; // can be undefined, but the variable exists
};
}
var toCheckLater = getChecker("jQuery");
Use
if (typeof jQuery === "undefined")
to check for undefined.
I don't quite get what you're trying to achieve, but I think you could do something like this
var toCheckLater = typeof jQuery; //if, for example, jQuery is defined you'll get "function"
// Some time later..
if (toCheckLater === 'undefined') {
}
Simply do this:
var scriptName = 'jQuery';
if( !window.hasOwnProperty(scriptName) ){
//jQuery is undefined
}
var checker = function(scriptArray) {
for(var i in scriptArray)
this[i] = i?i:loadScript(i); // make your own loadScript function
}
checker({'jquery','anothercode'});
//access checker.jquery / checker.anothercode
You could use something like this. Create a 'class' that load all the scripts.
You have use the typeof Method
typeof(variable_name) will give you "string", "object", "undefined" or "number" depending on the variable
typeof(jQuery) == "undefined"
is the way to go.
Your array of scripts:
var scripts = ['script1', 'jQuery'];
After loading the scripts you can use the same array and loop through it.
for (var i = 0, n = scripts.length; i !== n; i++) {
if (!window.scripts[i]) {
// falsy
}
}
This assumes that the scripts array references a global variable that the script will expose when loaded.
However, if I understand what you're going for, a better method would be to register a callback for when the appropriate script element is loaded. See these questions for some examples: (1), (2)
Code like this is pretty standard:
function loadScriptAsync(src, callback) {
var script = document.createElement('script'),
place = document.getElementsByTagName('script')[0];
script.type = "text/javascript";
script.async = true;
script.src = src;
script.onload = script.onreadystatechange = function() {
callback();
// clean up for IE and Opera
script.onload = null;
script.onreadystatechange = null;
};
place.parentNode.insertBefore(script, place);
}

jJavascript window.onload event correct usage

I have this loop code to reduce the DOM calls in my Javascript, and reuse them.
aarr = [];
for (var z=1; z<=10; z++) {
c = z-1;
aarr[c] = document.getElementById("a"+z);
}
I have been shown that if the code is ran before the DOM is complete, then the array is null. Moving the script after the last html code will work.
So now I want to put this code inside the window.onload event so to not have to move the script code to the bottom of the page. But it apparently does not work because it appears that the array loop is executed before the DOM is completed.
window.onload=function(){
var aarr = [];
for (var z=1; z<=10; z++) {
c = z-1;
aarr[c] = document.getElementById("a"+z);
}
}
Also, I have tried to remove the "var" to remove scope without making a difference.
You could also try this approach without using a framework:
window.onload = (function(){
return function(){
var aarr = [];
for (var z=1; z<=10; z++) {
aarr.push(document.getElementById("a"+z));
alert(aarr[z-1].id);
}
};
})();
JSFiddle
If you can use jquery, then you can use the document ready listener:
$(document).ready(function() {
var aarr = [];
for (var z=1; z<=10; z++) {
c = z-1;
aarr[c] = document.getElementById("a"+z);
}
});
http://www.jquery.com
as per the comment above, have you tried:
if (document.readyState === "complete") { init(); } // call whatever function u want.
The load event fires at the end of the document loading process. At this point, all of the objects in the document are in the DOM, and all the images and sub-frames have finished loading.
MDN - window.onload
I guess you try calling code outside of onload. See this fiddle
Better to use a function without pre-scanning the dom to create a cache, Pre-scanning is not needed when you use a simple function with a cache construction. With jQuery you can can create a function like this (native javascript method below this):
window.__jcache = {};
window.$jc = function(u) // jQuery cache
{
if( u == undefined )
{ return window.jQuery; }
if( typeof u == 'object' || typeof u == 'function' )
{ return window.jQuery(u); }
if( window.__jcache[u] == undefined )
{ window.__jcache[u] = window.jQuery(u); }
return window.__jcache[u];
};
Or without a framework (native javascript):
window.__domcache = {};
window.getObj = function(u) // jQuery cache
{
if( u == undefined )
{ return null; }
if( typeof u == 'object' || typeof u == 'function' )
{ return u; }
if( window.__domcache[u] == undefined )
{ window.__domcache[u] = document.getElementById(u); }
return window.__domcache[u];
};
So you can do:
var o = $jc('a1'); // for jquery version
var o = getObj('a1'); // The native javascript method (jamex)
That does the trick.
Greetz, Erwin Haantjes

Categories

Resources