Firefox innerHTML resets itself (for lack of a better way to put it)
I am creating a part of a website that requires people being able to create their own variables. But I ran into a snag.
Here is the portion of my code in question (explanation below):
var nextOpenVarNumber = 0;
var varFocusNumber = new Array();
function addVar()
{
if(nextOpenVarNumber==0)
{
document.getElementById("newVars").innerHTML+="<br />New custom variables:<br /><br />";
}
document.getElementById("newVars").innerHTML += "<div id=\"newVar"+nextOpenVarNumber+"Id\"><input type=\"text\" name=\"newVar"+nextOpenVarNumber+"Name\" value=\"Variable Name\" onfocus=\"javascript:clearIfNewFocus("+nextOpenVarNumber+",0);\"> = <input type=\"text\" name=\"newVar"+nextOpenVarNumber+"Value\" value=\"Variable Value\" onfocus=\"javascript:clearIfNewFocus("+nextOpenVarNumber+",1);\"> <a href=\"javascript:removeVar("+nextOpenVarNumber+");\">[-] Remove this variable</a><br /></div>";
varFocusNumber[nextOpenVarNumber] = new Array(0,0);
nextOpenVarNumber++;
}
function removeVar(varNumber)
{
document.getElementById("newVar"+varNumber+"Id").style.display = "none";
}
function clearIfNewFocus(varNumber, varPart)
{
if(varPart==0)
{
if(varFocusNumber[varNumber][0] == 0)
{
document.getElementsByName("newVar"+varNumber+"Name")[0].value = "";
}
}
if(varPart==1)
{
if(varFocusNumber[varNumber][1]==0)
{
document.getElementsByName("newVar"+varNumber+"Value")[0].value = "";
}
}
varFocusNumber[varNumber][varPart] = 1;
}
</script>
<div id="newVars"></div><a href="javascript:addVar();">[+] Add Custom variable</a>```
You can copy and paste it into a webpage to check it out. The problem is as follows:
Create a few new variables and give them names and values. But after you add the values, if you click on make new variable, it resets the already-named variables to the defaults. This happens only in Firefox. In IE it works fine. I read somewhere that someone else had similar problems, but no solution was offered. Any help or suggestions?
I think the problem is in the innerHTML, because if I alert its value before I change the var name and after I do it, it remains the same, with the default values.
You might want to try just directly setting (instead of appending) the initial innerHTML on var == 0 (in your add function). Also, instead of doing .innerHTML +=, try doing:
.innerHTML = .innerHTML + 'whatever'
I've had issues before with Javascript and both += and ++/–. I've also had issues before with Javascript not placing the variable at its current value when setting an event; that is, when it triggers an event on an element, sometimes that variable pulls its current value at the time of triggering, not at the time of assigning.
Anyways, those are initial things you can try to get it to work with the innerHTML modification approach.
The ideal approach, though, is to use DOM functions to insert the new elements. Instead of this:
.innerHTML = '<div id=\"newVar"+nextOpenVarNumber+"Id\"><input type=\"text\" name=\"newVar"+nextOpenVarNumber+"Name\" value=\"Variable Name\" onfocus=\"javascript:clearIfNewFocus("+nextOpenVarNumber+",0);\"> = <input type=\"text\" name=\"newVar"+nextOpenVarNumber+"Value\" value=\"Variable Value\" onfocus=\"javascript:clearIfNewFocus("+nextOpenVarNumber+",1);\"> <a href=\"javascript:removeVar("+nextOpenVarNumber+");\">[-] Remove this variable</a><br /></div>';
… you'd have something like this:
var newVarDiv = document.createElement('div'); var newVarName = document.createElement('input'); var newVarValue = document.createElement('input'); var newVarRemove = document.createElement('a');
newVarDiv.setAttribute('id', 'newVar'+nextOpenVarNumber+'Id');
newVarName.setAttribute('name', 'newVar'+nextOpenVarNumber+'Name'); newVarName.onfocus = function(){ clearIfNewFocus(nextOpenVarNumber,0); };
// … and so on, down to appending the elements with:
document.getElementById('newVars').appendChild(newVarDiv); newVarDiv.appendChild(newVarName); newVarDiv.appendChild(newVarValue); newVarDiv.appendChild(newVarRemove);
It's been a while since I've used Javascript DOM functions, so you'll probably need to work with that a bit.
ranma wrote: function removeVar(varNumber) { document.getElementById("newVar"+varNumber+"Id").style.display = "none"; }
DOM functions here, too. Instead of hiding it, remove it completely:
function removeVar(varNumber) { var removing = document.getElementById("newVar"+varNumber+"Id"); document.getElementById('newVars').removeChild(removing); }
Finally, your clearIfNewFocus function can be simplified a bit (I think) to read:
function clearIfNewFocus(varNumber, varPart) { if(varFocusNumber[varNumber][varPart] == 0) { document.getElementsByName("newVar"+varNumber+ (varPart ? "Value" : "Name") )[0].value = ""; }
varFocusNumber[varNumber][varPart] = 1; }
Edit: Disabled smilies.
Thanks for the first reply. I had already tried the first suggestion about the += as you said, but it didnt work. Not wanting to use Javascript DOM too much, I was hoping for some other fix.
My temporary workaround includes storing all new variables in an array when creating a new variable, then use the innerHTML, and fixing the values later based on my array. I know it's not elegant, but it will do for now.
Meanwhile, please keep suggestions coming. Thanks for the great and well-thought-out post! I will definitely look into Javascript DOM in the future to clean up my code.
ranma wrote: Not wanting to use Javascript DOM too much, I was hoping for some other fix. I will definitely look into Javascript DOM in the future to clean up my code.
Absolutely. For now, it's not a pressing concern but, as you start to develop more and more complex Javascript solutions, you'll often find that the quirks of manipulating the HTML directly will cause headaches cross-browser. One good example of this is the infamous innerHTML/outerHTML choice… which, now that I think about it, may be another way to attack your problem: outerHTML just includes the surrounding tag as well (<div id="newVars"></div>), so try that and just rewrite the element AND its contents.
Oh, and a good cheap way to check for IE vs. other browsers is to do this:
var ie = ( document.all ? true : false );
Only downside is that it classifies Opera as IE, but no one cares about Opera.
ranma wrote: Thanks for the great and well-thought-out post! No problem. :) I've dealt with stupid cross-browser Javascript issues a lot, and I know how frustrating it can be searching for that answer.
ranma wrote: My temporary workaround includes storing all new variables in an array when creating a new variable, then use the innerHTML, and fixing the values later based on my array. I know it's not elegant, but it will do for now.
Well, if you ever get the values to persist on the inputs, then this next series of comments is relevant… otherwise, it's just another bit of info:
Technically, since the elements exist on the page, you don't really need a variable array. Your variable array is represented in the newVars div with a series of child divs. So, you could probably access the names and values by doing this:
function getValue(num) { var container = document.getElementById('newVars'); var thisVar = container.getElementsByTagName('div')[(num-1)]; return thisVar.getElementsByName('valueInputName').value; }
… or, you could construct the id as in your code and getElementById() on container. Either way, you should be able to nest the scope of your getElement*() functions to go deeper into the divs.
Edit: Smilies again.
If i were u i would start searching for some AJAX.
If i remember correct JQuery handles such things kinda nice in a few lines of code :)
Check out the following link http://api.jquery.com/bind/
Don't know if i'm 100% correct here but it seems that that can tackle ur problem :)
MoshBat wrote: Doesn't the error console report problems with Javascript? Maybe see if it has anything to say.
Checked. It doesn't. It's the first place I looked. Code is clean. Apparently this was pointed to Bugzilla but Mozilla said it's not a bug. Ah well….
Thanks for the pointers! As to jQuery, is that supported in all browsers? Sorry if it's a stupid question.
michelfalke wrote:
-
If i were u i would start searching for some AJAX.
-
If i remember correct JQuery handles such things kinda nice in a few lines of code :)
-
Check out the following link http://api.jquery.com/bind/
Don't know if i'm 100% correct here but it seems that that can tackle ur problem :)
-
… No. AJAX has nothing to do with this unless he wants to store the variables outside of a single-use load of the page. AJAX is just an asynchronous way (using Javascript or any Javascript libraries) to make requests to a file without reloading the page.
-
Not always a few lines of code, but it certainly shortens regular Javascript code and can work easier cross-browser. :)
-
Nah, that's the function to bind an event to an element; that's relevant to what he's doing, but not really a solution. The functions he'd probably be most interested in would either be .html() or .append().
ranma wrote: Checked. It doesn't. It's the first place I looked. Code is clean. Apparently this was pointed to Bugzilla but Mozilla said it's not a bug. Ah well….
You should reopen the bug with your test case, then, unless they gave a suitable explanation for why this is not unexpected behavior. If they did, could you provide a link?
ranma wrote: As to jQuery, is that supported in all browsers? Sorry if it's a stupid question. Not a stupid question. jQuery is a library of functions written in Javascript using prototype functionality. Javascript is cross-browser, so jQuery is as well. You just need to include the library in a script tag.
jQuery does make writing cross-browser Javascript easier. I use it almost exclusively now, whereas I used to deal with these cross-browser quirks and such. I still have to deal with a few (from the IE family, of course), but not nearly as many as with Javascript.
That being said, I still use regular Javascript for some things. With jQuery, you're going to see a slight overhead when selecting elements and, sometimes, it's just more efficient to write more Javascript to do what jQuery is doing with more Javascript than you wrote (if that makes sense). This is mainly a factor in heavier applications or with a large number of elements being selected/worked with.
So, my advice? Stick with Javascript until you understand it well enough to appreciate what jQuery is doing behind the scenes to make your life easier (in most cases).