getElementById in 3 ways - javascript

I have an application that needs to retrieve a value out of a hidden input form field. However, this application has a base page which calls another page that is in an iFrame and then it also can call itself inside another iFrame:
default.asp -> screen.asp (in iFrame)
screen.asp -> a new instance of screen.asp (in iFrame)
document.getElementById('focusValue').value
window.frames[0].document.getElementById('focusValue').value
parent.frames[arrVal].document.getElementById('focusValue').value
When I reference the hidden input form field from default -> screen I can use the standard document.getElementById('focusValue').value;. Then when I'm in the 1st level iFrame I have to use window.frames[0].document.getElementById('focusValue').value;. Then when I'm in the 2+ levels in an iFrame I have to use the parent.frames[arrVal].document.getElementById('focusValue').value;.
A common structure that I'm starting to see is this:
if(document.getElementById('focusValue') == undefined){
window.frames[0].document.getElementById('focusValue').value = focusValue;
console.log('1');
}else if((parent.frames.length -1) == arrVal){
console.log('2');
if (arrVal > 0) {
parent.frames[arrVal].document.getElementById('focusValue').value = focusValue;
}
}else{
document.getElementById('focusValue').value = focusValue;
console.log('3');
}
Now I can certainly do this but outside of writing a novel worth of comments I'm concerned with other programmers(or me 1 month from now) looking at this code and wondering what I was doing.
My question is there a way to achieve what I'm looking to do in a standard form? I'm really hoping that there is a better way to achieve this.

I would suggest you have each page do the work of finding the value you want by calling a method. Basically exposing a lookup interface. Then you only need to call a method on the target page from the parent page. Proper naming will help developers understand what is going on and using methods will simplify the logic.
Or if you only need to get the value from the parent page, then you could register a hook with each page in an iframe using a common interface. Each page can just call that hook to get the value. This prevents your complex logic of determining what level the page is. Something like
iframe1.GetValueHook = this.GetValue;
iframe2.GetValueHook = this.GetValue;
Then each page can just call
var x = this.GetValueHook();
If you have nested pages, you could make this recursive. If you need communication between all pages then use the same approach but with a registration process. Each page registers itself (and it's children) with it's parent. But if you need to do this then you should reevaluate your architecture.
Example:
register.js
var __FRAMENAME = "Frame1";
var __FIELDID = "fieldId";
var __frames = [];
function RegisterFrame(frame) {
__frames.push(frame);
for (var i = 0; i < frame.children.length; i++) {
__frames.push(frame.children[i]);
}
RegisterWithParent();
}
function RegisterWithParent() {
var reg = {
name: __FRAMENAME,
getvalue: GetFieldValue,
children: __frames
};
if(parent != undefined && parent != this) {
parent.RegisterFrame(reg);
}
}
function SetupFrame(name, fieldId) {
__FRAMENAME = name;
__FIELDID = fieldId;
RegisterWithParent();
}
function GetFieldValue() {
return document.getElementById(__FIELDID).value;
}
function GetValueFrom(name) {
for (var i = 0; i < __frames.length; i++) {
if (__frames[i].name == name) {
return __frames[i].getvalue();
}
}
}
index.html
<html>
<head>
<script language="javascript" type="text/javascript" src="register.js"></script>
</head>
<body>
PAGE
<input type="hidden" id="hid123" value="123" />
<iframe id="frame1" src="frame1.html"></iframe>
<iframe id="frame2" src="frame2.html"></iframe>
<script type="text/javascript">
SetupFrame("Index", "hid123");
setTimeout(function () { //Only here for demonstration. Make sure the pages are registred
alert(GetValueFrom("frame3"));
}, 2000);
</script>
</body></html>
frame1.html
<html>
<head>
<script language="javascript" type="text/javascript" src="register.js"></script>
</head>
<body>
<input type="hidden" id="hid" value="eterert" />
<script type="text/javascript">
SetupFrame("frame1", "hid");
</script>
</body></html>
frame2.html
<html>
<head>
<script language="javascript" type="text/javascript" src="register.js"></script>
</head>
<body>
<input type="hidden" id="hid456" value="sdfsdf" />
<iframe id="frame2" src="frame3.html"></iframe>
<script type="text/javascript">
SetupFrame("frame2", "hid456");
</script>
</body></html>
frame3.html
<html>
<head>
<script language="javascript" type="text/javascript" src="register.js"></script>
</head>
<body>
<input type="hidden" id="hid999" value="bnmbnmbnm" />
<script type="text/javascript">
SetupFrame("frame3", "hid999");
</script>
</body></html>
This would be better if you can change it up to use a dictionary/hash tbale instead of loops.

Your best bet will be to set varables named correctly so it's self documenting. Something like this...
var screenFrame = window.frames[0];
var screenFrame2 = parent.frames[arrVal];
var value = screenFrame2.document.getElementById('focusValue').value
This will make it easier to read.

If you really must search frames for a given element, then you should just make your own function to do that and use that function everywhere. Put a lot of comments in the function explaining why/what you're doing and give the function a meaningful name so it will be more obvious to future programmers looking at your code what you are doing or where they can look to find what you are doing.
function setValueByIdFrames(name) {
if(document.getElementById(name) == undefined){
window.frames[0].document.getElementById(name).value = name;
console.log('1');
} else if((parent.frames.length -1) == arrVal){
console.log('2');
if (arrVal > 0) {
parent.frames[arrVal].document.getElementById(name).value = name;
}
} else {
document.getElementById(name).value = name;
console.log('3');
}
}

Related

How can I use a parameter to change HTML text?

I'm using an API, and am trying to access the value of product.shoeName to change text on my HTML page. This is my code:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript"
src="shoepoo.js">
</script>
</head>
<body>
<div>
<p id="text" style="color:purple;
font-weight:bold;font-size:20px;">
</p>
<script type="text/javascript"> shoeName(); </script>
</div>
</body>
</html>
const SneaksAPI = require('sneaks-api');
const sneaks = new SneaksAPI();
//getProducts(keyword, limit, callback) takes in a keyword and limit and returns a product array
function shoeName(){
sneaks.getProducts("Jumbo Blazer", 1, function(err, products){
products.forEach(
function names (product) {
document.getElementById("text").innerHTML = product.shoeName;
})
});
};
Basically, I want product.shoeName to be shown as text, but nothing is showing up. How can I fix this? I understand it's a local function which is probably stopping the data from being shown (or something like that), but how can I work around this?
Made below changes in shoepoo.js
products.forEach((product)=> {
document.getElementById("text").innerHTML = product.shoeName;
});
But you need to create dynamic HTML components if there is multiple data in products. Otherwise, it set the last shoeName in the paragraph component.

JavaScript function only works after page reload

I know this has been asked a lot on here, but all the answers work only with jQuery and I need a solution without it.
So after I do something, my Servlet leads me to a JSP page. My JS function should populate a drop down list when the page is loaded. It only works properly when the page is refreshed tho.
As I understand this is happening because I want to populate, using innerHTML and the JS function gets called faster then my HTML page.
I also get this error in my Browser:
Uncaught TypeError: Cannot read property 'innerHTML' of null
at XMLHttpRequest.xmlHttpRequest.onreadystatechange
I had a soulution for debugging but I can't leave it in there. What I did was, every time I opened that page I automatically refreshed the whole page. But my browser asked me every time if I wanted to do this. So that is not a solution that's pretty to say the least.
Is there something I could do to prevent this?
Edit:
document.addEventListener("DOMContentLoaded", pupulateDropDown);
function pupulateDropDown() {
var servletURL = "./KategorienHolen"
let xmlHttpRequest = new XMLHttpRequest();
xmlHttpRequest.onreadystatechange = function () {
if (xmlHttpRequest.readyState === 4 && xmlHttpRequest.status === 200) {
console.log(xmlHttpRequest.responseText);
let katGetter = JSON.parse(xmlHttpRequest.responseText);
JSON.stringify(katGetter);
var i;
for(i = 0; i <= katGetter.length -1; i++){
console.log(katGetter[i].id);
console.log(katGetter[i].kategorie);
console.log(katGetter[i].oberkategorie);
if (katGetter[i].oberkategorie === "B") {
document.getElementById("BKat").innerHTML += "" + katGetter[i].kategorie + "</br>";
} else if (katGetter[i].oberkategorie === "S") {
document.getElementById("SKat").innerHTML += "" + katGetter[i].kategorie + "</br>";
} else if (katGetter[i].oberkategorie ==="A") {
document.getElementById("ACat").innerHTML += "" + katGetter[i].kategorie + "</br>";
}
// document.getElementsByClassName("innerDiv").innerHTML = "" + katGetter.kategorie + "";
// document.getElementById("test123").innerHTML = "" + katGetter.kategorie + "";
}
}
};
xmlHttpRequest.open("GET", servletURL, true);
xmlHttpRequest.send();
}
It can depend on how + when you're executing the code.
<html>
<head>
<title>In Head Not Working</title>
<!-- WILL NOT WORK -->
<!--<script>
const p = document.querySelector('p');
p.innerHTML = 'Replaced!';
</script>-->
</head>
<body>
<p>Replace This</p>
<!-- Will work because the page has finished loading and this is the last thing to load on the page so it can find other elements -->
<script>
const p = document.querySelector('p');
p.innerHTML = 'Replaced!';
</script>
</body>
</html>
Additionally you could add an Event handler so when the window is fully loaded, you can then find the DOM element.
<html>
<head>
<title>In Head Working</title>
<script>
window.addEventListener('load', function () {
const p = document.querySelector('p');
p.innerHTML = 'Replaced!';
});
</script>
</head>
<body>
<p>Replace This</p>
</body>
</html>
Define your function and add an onload event to body:
<body onload="pupulateDropDown()">
<!-- ... -->
</body>
Script needs to be loaded again, I tried many options but <iframe/> works better in my case. You may try to npm import for library related to your script or you can use the following code.
<iframe
srcDoc={`
<!doctype html>
<html>
<head>
<style>[Style (If you want to)]</style>
</head>
<body>
<div>
[Your data]
<script type="text/javascript" src="[Script source]"></script>
</div>
</body>
</html>
`}
/>
Inside srcDoc, it's similar to normal HTML code.
You can load data by using ${[Your Data]} inside srcDoc.
It should work :
document.addEventListener("DOMContentLoaded", function(){
//....
});
You should be using the DOMContentLoaded event to run your code only when the document has been completely loaded and all elements have been parsed.
window.addEventListener("DOMContentLoaded", function(){
//your code here
});
Alternatively, place your script tag right before the ending body tag.
<body>
<!--body content...-->
<script>
//your code here
</script>
</body>

localstorage not retaining data after page reload

I am trying to retain data in a localstorage after reload but it is not working
this is my attempt
<script>
window.onbeforeunload = function() {
localStorage.setItem(name, $('#inputName').val());
}
window.onload = function() {
var name = localStorage.getItem(name);
if (name !== null) $('#inputName').val(name);
alert(name);
}
</script>
<html>
<body>
<input type="text" id="inputName" placeholder="Name" required>
</body>
</html>
on refreshing the page after entering data on the form it keeps alerting null. kindly assist
In your onbeforeunload, name is the name of the window (because you haven't given it any other value, and browsers have a global name property which is the name of the window — it's usually blank).
In this line:
var name = localStorage.getItem(name);
...it's undefined, because of the var name.
You need to use a proper name, for instance:
window.onbeforeunload = function() {
localStorage.setItem("your-setting-name", $('#inputName').val());
};
window.onload = function() {
var name = localStorage.getItem("your-setting-name");
if (name !== null) $('#inputName').val(name);
alert(name);
};
Also note charlietfl's oint that if you don't want to alert null on the first visit to the page, you need to put the alert in the body of the if:
window.onload = function() {
var name = localStorage.getItem("your-setting-name");
if (name !== null) {
$('#inputName').val(name);
alert(name);
}
};
Otherwise, it'll alert null on the first visit and then whatever the last value was otherwise.
(Also note that I've added some missing ;. Automatic Semicolon Insertion will add these particular ones, but it's an error-correction mechanism, so I'd advise not relying on it.)
Other issues:
You're using jQuery functions, but haven't shown any script tag including jQuery on the page.
You have the closing </html> tag before the <input ...> tag.
Here's a fiddle with the above fixed (can't use Stack Snippets with local storage): https://jsfiddle.net/un86not0/ Full working page:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<title>Example</title>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script>
window.onbeforeunload = function() {
localStorage.setItem("your-setting-name", $('#inputName').val());
};
window.onload = function() {
var name = localStorage.getItem("your-setting-name");
if (name !== null) {
$('#inputName').val(name);
alert(name);
}
};
</script>
<input type="text" id="inputName" placeholder="Name" required>
</body>
</html>
The variable name haven't been initiated yet you already used it as a value reference. Maybe it wasn't working well because of that?
Here in this solution, you can separately reference the local storage item without using the variable name which might have caused it not to work.
<script>
window.onbeforeunload = function() {
localStorage.setItem('myItem', $('#inputName').val());
}
window.onload = function() {
var name = localStorage.getItem('myItem');
if (name !== null) $('#inputName').val(name);
alert(name);
}
</script>

Why can't javascript find my functions?

I made a puzzle game using HTML5, just now I tried to add local storage to the game, but failed.
I wrote three functions. The problem is: If I put all the functions in one .js file, none is defined when debugging(via chrome). If I split these three functions to another file and add a tag to the .html file, I'm told these are not defined.
So how to solve this problem?
Sorry for my poor English, hope you understand what I means.
Here are my functions and html file.
<html>
<head>
<meta charset="utf-8">
<title>Puzzle</title>
<script src="puzzle-localstorage.js"></script>
<script src="puzzle.js"></script></script>
</head>
<body onLoad="Init()" onkeydown="keydown()">
<p align="center">
<canvas id="board" height="600" width="600" style="border-style:double">
Your Browser doesn't support canvas
</canvas>
</p>
<p id="moves">Moves: <span id="movecount">0</span>
<input type="number" id="boardEdgeNum" value="3"/>
<input type="file" id="imgSrc"/>
</p>
function supportsLocalStorage() {
try {
return 'localStorage' in window && window['localStorage'] !== null;
} catch (e) {
return false;
}
}
function saveGameState() {
if (!supportsLocalStorage()) { return false; }
localStorage["puzzle.boardEdge"] = boardEdge;
localStorage["puzzle.blockPixel"] = blockPixel;
for (var i = 0; i < boardEdge; i++) {
for(var j=0;j<boardEdge;j++){
localStorage["puzzle.gameStatus."+i+j] = gameStatus[i][j];
}
}
localStorage["puzzle.image.src"]=imgElement.src;
localStorage["puzzle.move.count"] = moveCount.textContent;
if(gameInProgress)localStorage["puzzle.game.in.progress"] = "true";
else localStorage["puzzle.game.in.progress"]="false";
localStorage["puzzle.empty.block.X"] = emptyBlock.X;
localStorage["puzzle.empty.block.Y"] = emptyBlock.Y;
return true;
}
function resumeGame() {
if (!supportsLocalStorage()) {return false;}
if(!localStorage["puzzle.game.in.progress"]=="true"){return false;}
boardEdge=parseInt(localStorage["puzzle.boardEdge"]);
blockPixel=parseInt(localStorage["puzzle.blockPixel"]);
imgElement=new Image();
imgElement.src=localStorage["puzzle.image.src"];
gameStatus=new Array(boardEdge);
gameCompStatus=new Array(boardEdge);
for (var i = 0; i < boardEdge; i++) {
gameStatus[i]=new Array(boardEdge);
gameCompStatus[i]=new Array(boardEdge);
for(var j=0;j<boardEdge;j++){
gameStatus[i][j]=parseInt(localStorage["puzzle.gameStatus."+i+j]);
var x=(gameStatus[i][j]-1)%boardEdge;
var y=(gameStatus[i][j]-1-j)/boardEdge;
drawingContext.drawImage(imgElement,x*blockPixel,y*blockPixel,blockPixel,blockPixel
j*blockPixel,i*blockPixel,blockPixel,blockPixel);
drawLines();
}
}
gameStatus[boardEdge-1][boardEdge-1]=0;
gameCompStatus[boardEdge-1][boardEdge-1]=0;
moveCount.textContent=localStorage["puzzle.move.count"];
gameInProgress=(localStorage["puzzle.game.in.progress"] =="true");
emptyBlock=new Cell(parseInt(localStorage["puzzle.empty.block.X"]),parseInt(localStorage["puzzle.empty.block.Y"]));
return true;
}
<script src="puzzle.js"></script></script>
What is this? Is it typo? Or in your real code it is so too? Try to remove them. Javascript should see your functions. Where is declarations for Init and keydown functions? Does javascript see them?
Have you checked for any errors? I see one in the loop of resumeGame:
drawingContext.drawImage(imgElement,x*blockPixel,y*blockPixel,blockPixel,blockPixel
j*blockPixel,i*blockPixel,blockPixel,blockPixel);
should probably be:
drawingContext.drawImage(imgElement,x*blockPixel,y*blockPixel,blockPixel,blockPixel,
j*blockPixel,i*blockPixel,blockPixel,blockPixel);
Your url might be wrong. You are using a relative url instead of an absolute url, consequently the JS file must be in the same folder as the HTML Document.
Try an absolute url (e.g. http://www.servername.com/puzzle/js/puzzle.js") instead and check if that accomplishes anything.

How do you use $('document').ready(function()) in jQuery?

I have a piece of code that is working fine in IE, but it doesn’t run in Firefox. I think the problem is that I have not been able to implement $('document').ready(function). The structure of my json is like [{"options":"smart_exp"},{"options":"user_intf"},{"options":"blahblah"}].
I will be very thankful if someone can see my code & help me in correctly implementing it. Here is my code:
<html><head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2
/jquery.min.js"></script>
<script type="text/javascript" language="javascript">
$(document).ready(function() {
$.getJSON("http://127.0.0.1/conn_mysql.php", function (jsonData) {
$.each(jsonData, function (i, j) {
document.form1.fruits.options[i] = new Option(j.options);
});});
});
</script></head>
<body><form name="form1">
My favourite fruit is :
<select name="fruits" id="fruits" /></form></body>
</html>
Short version (suggested by meeger): don't use single quotes around document.
document is a variable that comes with JavaScript (at least in the browser context). Instead, try the following for the relevant line.
$(document).ready(function() {
You'll also want to take the onLoad attribute off of the body tag, else it will run twice.
Just run $(document).ready(function() {doStuff}). This will automatically run when the document is ready.
It's best practice, at least in my opinion, that you don't put any events in the html itself. This way you separate the structure of an html document from it's behavior. Instead attach events in the $(document).ready function.
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$.getJSON("http://localhost/conn_mysql.php", function (jsonData) {
var selectElem = $('#fruits');
for(var i = 0; i < jsonData.length; i++) {
selectElem.append($('<option>').html(jsonData[i].options));
}
});
});
</script>
</head>
<body>
<form name="form1">
My favourite fruit is :
<select name="fruits" id="fruits" />
</form>
</body>
</html>
EDIT:
I tested with the following and mocked the json object since I can't make that call myself.
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
var jsonData = JSON.parse('[{"options":"smart_exp"},{"options":"user_intf"},{"options":"blahblah"}]');
var selectElem = $('#fruits');
for(var i = 0; i < jsonData.length; i++) {
selectElem.append($('<option>').html(jsonData[i].options));
}
});
</script>
</head>
<body>
<form name="form1">
My favourite fruit is :
<select name="fruits" id="fruits" />
</form>
</body>
</html>
Here it is in all its glory. The shorthand, awesome version:
UPDATED
<script type="text/javascript" language="javascript">
$(function() {
$.getJSON("http://localhost/conn_mysql.php", function (jsonData) {
var cacheFruits = $('#fruits'),
cacheOption = $(document.createElement('option'));
$.each(jsonData, function (i, j) {
cacheFruits.append(
cacheOption.clone().attr('value', j.options).html(j.options)
);
});
});
});
</script>
Of course, I don't know what your JSON structure is, so you may need to play around with the append section of the code.
There should be no reason why the above would not work.
You do not need quotes around document. Once the page has completely loaded, it will start executing whatever you have defined in ready()
$(document).ready(function() {
$(this).getJSON("http://localhost/conn_mysql.php", function (jsonData) {
$(this).each(jsonData, function (i, j) {
document.form1.fruits.options[i] = new Option(j.options);
});
});
});
Try this, your json data should be in this format:
[{'text':'sometext','value':'somevalue'},{'text':'sometext','value':'somevalue'}];
$(document).ready(function() {
$(this).getJSON("http://localhost/conn_mysql.php", function (jsonData) {
var options = [];
$.each(jsonData, function (i, j) {
options.push('<option value="' + j.value + '">' + j.text + '</option>');
});
$('#fruits').html( options.join(''));
});
});
Please note that there may be an encoding/escaping issues here.
Make sure that you escape the text properly from the server side.
htmlentities, htmlspecialchars can help you with that.
This should work in most browsers

Categories