Too much recursion - javascript

can anyone tell me where the loop comes from?
JS:
if (zahl > 1) {
document.getElementById('makroclickm2').innerHTML = data_split[zahlm2];
document.getElementById('makroclickm2').onclick = getwords(zahlm2++);
}
else {
document.getElementById('makroclickm2').innerHTML = "";
document.getElementById('makroclickm2').onclick = "";
}
if (zahl > 0) {
document.getElementById('makroclickm1').innerHTML = data_split[zahlm1];
document.getElementById('makroclickm1').onclick = getwords(zahlm1++);
}
else {
document.getElementById('makroclickm1').innerHTML = "";
document.getElementById('makroclickm1').onclick = "";
}
document.getElementById('makroclick').innerHTML = data_split[zahl];
document.getElementById('makroclick').onclick = getwords(zahl++);
document.getElementById('makroclickp1').innerHTML = data_split[zahlp1];
document.getElementById('makroclickp1').onclick = getwords(zahlp1++);
if (typeof(data_split[zahlp1]) == "undefined") {
document.getElementById('makroclickp1').innerHTML = "";
document.getElementById('makroclickp1').onclick = "";
}
document.getElementById('makroclickp2').innerHTML = data_split[zahlp2];
document.getElementById('makroclickp2').onclick = getwords(zahlp2++);
if (typeof(data_split[zahlp2]) == "undefined") {
document.getElementById('makroclickp2').innerHTML = "";
document.getElementById('makroclickp2').onclick = "";
}
HTML:
<div id="makroclickm2" onclick="" class="makroclick"></div>
<div id="makroclickm1" onclick="" class="makroclick"></div>
<div id="makroclick" onclick="getwords(0);" class="makroclick_center"></div>
<div id="makroclickp1" onclick="getwords(1);" class="makroclick"></div>
<div id="makroclickp2" onclick="getwords(2);" class="makroclick"></div>
(Not complete Code)
The function is called once onload.
Thx in advance!

In the lines like this:
document.getElementById('makroclickm2').onclick = getwords(zahlm2++);
You're assigning the onclick handler to the result of getwords(zahlm2++), not to that function itself.
If, as I suspect, the code above actually is the getwords function, that means it's calling itself (recursively).
Instead, write:
document.getElementById('makroclickm2').onclick = function() {
getwords(zahlm2++);
}

This doesn't answer the question (or even try to). However, it works to address the over-abundance of repeated code.
// instead of repeating the document.getElementById
// many times over...
document.getElementById('makroclickm2').innerHTML = "";
document.getElementById('makroclickm2').onclick = "";
// get the element once
var elm = document.getElementById('makroclickm2')
// and use it many times over
elm.innerHTML = ""
elm.onclick = null // do not use strings here
This will make the code much easier to follow (please use appropriate variable names).
Also, do not use strings with the onclick attribute. Use functions instead.
Happy coding.

You also might consider using event registration rather than direct assignment. That way you don't have to worry about accidentally overwriting anything later down the road. #Alnitak's solution would look more like this:
var myEl = document.getElementById('makroclickm2');
var myFunc = function() {
getwords(zahlm2++);
}
if (myEl.addEventListener) myEl.addEventListener("click", myFunc, false);
else if (myEl.attachEvent) myEl.attachEvent("onclick", myFunc);
else myEl.onclick = myFunc;
Obviously that's pretty verbose, but it would be easy to write a quick helper function takes myEl and myFunc as inputs and handles everything for you.
You can read more about event registration at http://www.quirksmode.org/js/events_advanced.html

This part might give you a ton of problems:
if (zahl > 1) {
document.getElementById('makroclickm2').innerHTML = data_split[zahlm2];
document.getElementById('makroclickm2').onclick = getwords(zahlm2++);
}
else {
document.getElementById('makroclickm2').innerHTML = "";
document.getElementById('makroclickm2').onclick = "";
}
if (zahl > 0) {
document.getElementById('makroclickm1').innerHTML = data_split[zahlm1];
document.getElementById('makroclickm1').onclick = getwords(zahlm1++);
}
else {
document.getElementById('makroclickm1').innerHTML = "";
document.getElementById('makroclickm1').onclick = "";
}
Try using else if instead of another block of if statements. Also, I'd use function(){} instead of "" (and getwords(), as that evaluates the function and doesn't set it to be run when the even is called):
if (zahl > 1) {
document.getElementById('makroclickm2').innerHTML = data_split[zahlm2];
document.getElementById('makroclickm2').onclick = function(){getwords(zahlm2++)};
} else if (zahl > 0) {
document.getElementById('makroclickm1').innerHTML = "";
document.getElementById('makroclickm1').onclick = null;
document.getElementById('makroclickm1').innerHTML = data_split[zahlm1];
document.getElementById('makroclickm1').onclick = function(){getwords(zahlm1++)};
} else {
document.getElementById('makroclickm2').innerHTML = "";
document.getElementById('makroclickm2').onclick = null;
}

Related

Make a function only run once (Javascript)

So I'm trying to create a function which changes the 0 slot of an array to an input value. However I want this function to only be able to run once. How do I do this, any help is greatly appreciated thanks.
function submitForm() {
$('#inputForm').submit;
if ($("#inputValue").val() != inputException) {
charSetName();
$("#inputValue").val("");
}
$("#inputValue").val("");
}
function charSetName() {
var nameSet = false;
if (nameSet == false) {
nameSet = true;
charDetails[0] = $("#inputValue").val();
document.getElementById("name").innerHTML = "<li id='name''>Name: " + charDetails[0] + "</li>";
}
}
This is an old question but I was brought here because I needed something similar.
To anyone who comes next time, here was what I eventually did:
I simply declared a variable with an initial count of 0.
Then every time my function runs, it auto increases.
The code I want to run once just checks if the count is 1, then it runs. If not, it doesnt.
Like this:
let count = 0;
count === 1 ? doSomething : doNothing
count++
Does it help?
Try this, I have defined isFunctionCalled:Boolean variable for handle it.
var isFunctionCalled = false;
function submitForm() {
$('#inputForm').submit;
if ($("#inputValue").val() != inputException) {
if (!isFunctionCalled) {
charSetName();
}
$("#inputValue").val("");
}
$("#inputValue").val("");
}
function charSetName() {
var nameSet = false;
if (nameSet == false) {
nameSet = true;
charDetails[0] = $("#inputValue").val();
document.getElementById("name").innerHTML = "<li id='name''>Name: " + charDetails[0] + "</li>";
}
isFunctionCalled = true;
}
Mind the executed variable:
var something = (function() {
var executed = false;
return function () {
if (!executed) {
executed = true;
// do something
}
};
})();
There are a lot of ways to do this.
Just a simple way is to set a flag value.
if(flag){
//your code here...
flag = !flag;
}
SO, if the value of the flag is 1 at first it will work. Then as the flag value is changed to 0, then the next time it is called, it will not be invoked, as flag is 0.

Avoid double getElementId's within else if

I have a long list of else if statements.
Each one does a document.getElementById to check for existence of some element.
In one of of the else if statements to the bottom i need to not only do getElementById but I need to check also if that element has a certain attribute. This made me do getElementById twice, which i was hoping to avoid.
This is my code:
if (doc.getElementById('blah')) {
} else if (doc.getElementById('blah2')) {
} else if (doc.getElementById('js_blob') && doc.getElementById('js_blob').hasAttribute('action')) {
//here
} else if (doc.getElementById('blah3')) {
} else if (doc.getElementById('blah4')) {
} else {
console.warn('none of them');
}
Notice the line: } else if (doc.getElementById('js_blob') && doc.getElementById('js_blob').hasAttribute('action')) {
I had tried something like this and it didnt work: } else if (var myBlobL = doc.getElementById('js_blob') && myBlobL.hasAttribute('action')) { this would give syntax error
anyway to avoid doing double getElementById in this else if statement?
Thanks
Use a temporary variable:
var tmp;
// ...
} else if ((tmp = doc.getElementById('js_blob')) && tmp.hasAttribute('action')) {
You can save the result in a variable, in this case you only once will call getElementById
var js_blob = doc.getElementById('js_blob')
if (js_blob && js_blob.hasAttribute('action')) {
}
I see that you have logic with many "else if", I think you can replace it on something like this
function fn() {
var ids = ['elem1', 'elem2', 'elem3'],
len = ids.length,
i, el;
for (i = 0; i < len; i++) {
el = document.getElementById(ids[i]);
if (el) {
break;
}
}
if (!el) {
return;
}
// work with el which has action
// or add logic for specific ID
if (el.hasAttribute('action')) {
el.innerHTML = 'action';
} else if (el.getAttribute('id') === 'elem2') {
el.innerHTML = 'ELEM2';
}
}
fn();
Need decrease count appeals to the DOM, in this case you just once will appeal to each element, and further will work only with copy.

Retrieve the "Placeholder" value with Javascript in IE without JQuery

I have some Javascript code that checks if a browser supports Placeholders and if it doesn't it creates them itself. Now this works on some older browsers but not all, especially IE.
All I need to do it get the "Placeholder" value, at the moment the placeholder in IE9 is "undefined".
Here is my code:
//Test if Placeholders are supported
var test = document.createElement("input");
if ("placeholder" in test) {
var testholder = true;
}
else {
var testholder = false;
}
//Fix unsupported placeholders
function placeHolder(id)
{
var demo = document.getElementById(id);
demo.className = "fix-hint";
demo.value = demo.placeholder;
demo.onfocus = function()
{
if (this.className == "fix-hint")
{
this.value = ""; this.className = "fix-nohint";
}
};
demo.onblur = function()
{
if (this.value === "")
{
this.className = "fix-hint"; this.value = demo.placeholder;
}
};
return false;
}
I am using 0% Jquery, I feel it's too bulky to solve small problems, plus I want to learn pure Javascript. Modernizr is a no too although I may come round to using it at some point.
UPDATE
This is the working code. Tested in IE 8 and 9. (The function call is within an if/else for "placeSupport".)
//Check if placeholders are supported
placeholderSupport = ("placeholder" in document.createElement("input"));
if(!placeholderSupport){
var placeSupport = false;
}else{
var placeSupport = true;}
//Support placeholders in older browsers
function placeHolder (id)
{
var el = document.getElementById(id);
var placeholder = el.getAttribute("placeholder");
el.onfocus = function ()
{
if(this.value == placeholder)
{
this.value = '';
this.className = "fix-nohint";
}
};
el.onblur = function ()
{
if(this.value.length == 0)
{
this.value = placeholder;
this.className = "fix-hint";
}
};
el.onblur();
}
If you're not sure if you're able to use certain functionality/attributes, try caniuse.com - you'll notice that placeholder is not available in IE9.
Try using getAttribute("placeholder")
getAttribute() returns the value of the named attribute on the
specified element. If the named attribute does not exist, the value
returned will either be null or "" (the empty string); see Notes for
details.
EXAMPLE
HTML
<input id="demo" placeholder="Rawr" />
JavaScript
var placeholder = document.getElementById("demo").getAttribute("placeholder");
console.log(placeholder);

Jquery .each() Scope Problem (bug?)

For some reason my call to nested jQuery.each() functions are losing scope for some variables, but not others. In the code below, the Client.KNE reference works, but ClientDiv does not, even though prior to that each, both are defined, populated variables...
By switching Client and ClientDiv to global variables, it works, but I feel like I should not have to create global variables here...
Doesn't Work:
jQuery.each(Messages.Additions, function (clientIndex) {
var Client = Messages.Additions[clientIndex];
var ClientDiv = $("#clientTitle_" + Client.ClientID);
if (ClientDiv.length == 0) {
$("#ClientTemplate").tmpl(Client).appendTo("#ClientContainer");
} else {
jQuery.each(Client.KNE, function (kneIndex) {
var KNE = Client.KNE[kneIndex]; // Works
var KNEDiv = ClientDiv.find("#kneTitle_" + KNE.KNE); // DOES NOT WORK
Does Work:
jQuery.each(Messages.Additions, function (clientIndex) {
Client = Messages.Additions[clientIndex];
ClientDiv = $("#clientTitle_" + Client.ClientID);
if (ClientDiv.length == 0) {
$("#ClientTemplate").tmpl(Client).appendTo("#ClientContainer");
} else {
jQuery.each(Client.KNE, function (kneIndex) {
KNE = Client.KNE[kneIndex]; // Works
KNEDiv = ClientDiv.find("#kneTitle_" + KNE.KNE); // Works
Anyone know what I'm doing wrong in the first version? Or is this a bug? Why does the one variable work but the other doesn't...
From here: Jquery $().each method obscures 'this' keyword it looks like I could pass the variables into the function call, but should I have to?
Tried the above link, and it is not working:
jQuery.each(Messages.Additions, function (clientIndex) {
var Client = Messages.Additions[clientIndex];
var ClientDiv = $("#clientTitle_" + Client.ClientID);
if (ClientDiv.length == 0) {
$("#ClientTemplate").tmpl(Client).appendTo("#ClientContainer");
} else {
jQuery.each(Client.KNE, function (kneIndex, Client, ClientDiv) {
var KNE = Client.KNE[kneIndex];
var KNEDiv = ClientDiv.find("#kneTitle_" + KNE.KNE); //Does not work - ClientDiv undefined
Similar questions without satisfactory answer:
Scope of jQuery each() function?
SOLUTION
$.each(Messages.Additions, function () {
var $Client = this;
var $ClientDiv = $("#clientTitle_" + $Client.ClientID);
if (!$ClientDiv.length) {
$("#ClientTemplate").tmpl($Client).appendTo("#ClientContainer");
} else {
$.each($Client.KNE, function () {
var $KNE = this;
var $KNEDiv = $ClientDiv.find("#kneTitle_" + jq($KNE.KNE));
// SWITCHED TO $ PREFIX
You can try this using this keyword which points to the current item in the loop. Instead of checking for if (ClientDiv == null) you should check for if (ClientDiv.length > 0) because jQuery returns am empty object if it do not finds the element so that check will fail.
var additions;
jQuery.each(Messages.Additions, function () {
var $clientDiv = $("#clientTitle_" + this.ClientID);
if ($clientDiv.length == 0) {
$("#ClientTemplate").tmpl(Client).appendTo("#ClientContainer");
} else {
jQuery.each(Client.KNE, function () {
$clientDiv.find("#kneTitle_" + this.KNE);
});
}
});

Defining prototype property for JavaScript for XML prototype functions

I am using custom javascript functions provided at this link (http://km0.la/js/mozXPath/) to implement particular XML functionality in FireFox.
Here is the code:
// mozXPath
// Code licensed under Creative Commons Attribution-ShareAlike License
// http://creativecommons.org/licenses/by-sa/2.5/
if( document.implementation.hasFeature("XPath", "3.0") ) {
if( typeof XMLDocument == "undefined" ) { XMLDocument = Document; }
XMLDocument.prototype.selectNodes = function(cXPathString, xNode) {
if( !xNode ) { xNode = this; }
var oNSResolver = this.createNSResolver(this.documentElement);
var aItems = this.evaluate(cXPathString, xNode, oNSResolver,
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
var aResult = [];
for( var i = 0; i < aItems.snapshotLength; i++) {
aResult[i] = aItems.snapshotItem(i);
}
return aResult;
}
XMLDocument.prototype.selectSingleNode = function(cXPathString, xNode) {
if( !xNode ) { xNode = this; }
var xItems = this.selectNodes(cXPathString, xNode);
if( xItems.length > 0 ){ return xItems[0]; }
else{ return null; }
}
Element.prototype.selectNodes = function(cXPathString) {
if(this.ownerDocument.selectNodes) {
return this.ownerDocument.selectNodes(cXPathString, this);
}
else { throw "For XML Elements Only"; }
}
Element.prototype.selectSingleNode = function(cXPathString) {
if(this.ownerDocument.selectSingleNode) {
return this.ownerDocument.selectSingleNode(cXPathString, this);
}
else { throw "For XML Elements Only"; }
}
}
Assuming the XML object has been defined and loaded with XML content, here is an example of how one would access a an XML tag named "cd_rank":
var cd_rank_XMLObj = XMLObj.selectSingleNode("cd_rank");
What I want to do is add the property "nodeTypedValue" to the selectSingleNode() function, but I'm not sure how to do this. In the Element.prototype.selectSingleNode function, I tried adding:
this.prototype.nodeTypedValue = this.textContent;
However, it's giving me an error saying it's undefined. I even tried adding it outside of the function, just to dumb it down and get the concept, and it also says it's undefined:
var XMLObj.selectSingleNode.prototype.nodeTypedValue = XMLObj.textContent;
alert(XMLObj.selectSingleNode("cd_rank").nodeTypedValue);
Essentially what I'm trying to do, I suppose, is add a prototype property to a prototype function. But I need some help with this. How can i add "nodeTypedValue" such that I write "XMLObj.selectSingleNode(Path).nodeTypedValue"?
Okay, I think I figured out how to add it inside the function, probably due more to luck than logic:
Element.prototype.selectSingleNode = function(cXPathString){
if(this.ownerDocument.selectSingleNode) {
var result = this.ownerDocument.selectSingleNode(cXPathString, this);
if (result != null) {
result.nodeTypedValue = result.textContent;
}
return result;
}
else{throw "For XML Elements Only";}
}

Categories

Resources