Hi I have an issue with onclick events being writen using innerHTML I have tried doing it two ways and both have not work
the function it needs to call is
function loadnewsstory()
{
alert("123456");
}
at the moment it should show the alert box with 123456 but it is not firing.
the function loading it is the following
function newsstories()
{
document.getElementById("activecontent").innerHTML = "<h1 class='newsheader'>Latest News</h1>";
xmlhttp=new XMLHttpRequest();
xmlhttp.open("POST","test.com?uri=loadnews",false);
xmlhttp.send();
var newsreponse = JSON.parse(xmlhttp.responseText);
var countstories = 0;
for (var i = 0, len = newsreponse.length; i < len; ++i) {
var news = newsreponse[i];
if(i % 2 == 0){
cssclass = "even";
}
else
{
cssclass = "odd";
}
// alert(news.featured_image);
document.getElementById("activecontent").innerHTML += "<div class='news " + cssclass + "'><div class='newstitle'><div class='newstitlecolor'><a href='#' onclick='loadnewsstory();'>" + news.post_title + "</a></div></div><div class='base' style='background: url('" + news.featured_image + "');'><img src='" + news.featured_image + "' style='width:100%; height:100%;' id='news_"+ countstories +"'/></div></div>";
document.getElementById("news_"+countstories).onclick = function(){ loadnewsstory();}
countstories++;
}
}
as you can see I have also ran document.getElementById("news_"+countstories).onclick = function(){ loadnewsstory();} because i read that onclick events could not be written by javascript innerHTML which I know I have been able to do before. If someone else knows of a fix to this issue that would be great. this is for a cordova iphone app
Thanks
EDIT
I have found that this
document.getElementById("activecontent").innerHTML += "<div class='news " + cssclass + "'><a href='javascript:openextlink();'><img src='" + news.featured_image + "' style='width:100%; height:100%;'/></a></div>";
works but it seems to only work on the last news story, am I missing something.
I suspect it's because your request is attempting to read/parse the response from the server too soon here:
xmlhttp.send();
var newsreponse = JSON.parse(xmlhttp.responseText);
Because this is an asyncronus (Ajax) request you need to give the script time to wait for the server to respond. You do this by creating an event handler that waits for the response.
xmlhttp.onreadystatechange=function() { // checks if the state of the request has changed
if (xmlhttp.readyState==4 && xmlhttp.status==200) { // checks that the response is ready
// code to handle the response here
var newsreponse = JSON.parse(xmlhttp.responseText);
// etc.
}
}
Also note that you should create this handler before calling xmlhttp.send();
First of all, appending to innerHTML is usually very bad. If you run the code like something.innerHTML += 'lots of html' in a loop, browser has to update the DOM tree and re-render the page on every iteration. This may greatly slow down the things. Use the buffer string instead.
I also suspect that this might have caused issues with event attachment. Try attaching events after all the divs have been attached to the tree. The code in this case would be something like this:
function newsstories()
{
// Use a variable that would store the newly generated HTML:
var html = "<h1 class='newsheader'>Latest News</h1>";
xmlhttp=new XMLHttpRequest();
xmlhttp.open("POST","test.com?uri=loadnews",false);
xmlhttp.send();
var newsreponse = JSON.parse(xmlhttp.responseText);
for (var i = 0, len = newsreponse.length; i < len; ++i) {
var news = newsreponse[i];
// Notice the 'var' keyword!
if(i % 2 == 0){
var cssclass = "even";
} else {
var cssclass = "odd";
}
// Append to our buffer variable
html += "<div class='news " + cssclass + "'><div class='newstitle'><div class='newstitlecolor'><a href='#' onclick='loadnewsstory();'>" + news.post_title + "</a></div></div><div class='base' style='background: url('" + news.featured_image + "');'><img src='" + news.featured_image + "' style='width:100%; height:100%;' id='news_"+ i +"'/></div></div>";
}
// Now that new html is ready, insert it into the tree
// and attach events
document.getElementById("activecontent").innerHTML = html;
for (var i = 0, len = newsreponse.length; i < len; ++i) {
var img = document.getElementById('news_'+i);
if(img) img.addEventListener('click', loadnewsstory);
}
}
it was due to z-index in my css that this was not working, I have fixed this by removing z-index:-1 and now all works fine, it is interesting that it was due to a css error that this bug come to alight
Related
So I have a search page that I'm working on that has a given JSON object as a return. When I click the search button, it's supposed to load up the results page (without a refresh), with the JSON parsed and placed neatly in div's using JS (I can't use jQuery) (this code is in ajax_info.html). Everything independently works. However, when I try to use AJAX with JavaScript, it doesn't load. Again, everything works when loaded independently. But right now, no scripts are working inside the script tag of ajax_info.html. Is there a better method that I could use to update the page with the results page without reloading? This is my code:
function loadDoc() {
var setInnerHTML = function(elm, html) {
elm.innerHTML = html;
Array.from(elm.querySelectorAll("script")).forEach( oldScript => {
const newScript = document.createElement("script");
Array.from(oldScript.attributes)
.forEach( attr => newScript.setAttributes(attr.name, attr.value) );
newScript.appendChild(document.createTextNode(oldScript.innerHTML));
oldScript.parentNode.replaceChild(newScript, oldScript);
});
}
console.log('hello');
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200 && xhttp.readyState == XMLHttpRequest.DONE) {
setInnerHTML(document.getElementById("demo"),this.responseText);
console.log(this.responseText);
}
};
xhttp.open("POST", "ajax_info.html", true);
xhttp.send();
}
and this is the relevant code for ajax_info.html:
<script>
alert("hello");
console.log('adfasdf');
const searchResults = {
//Json stuff
}
// console.log(searchResults);
//const obj = JSON.parse(searchResults);
//document.getElementById("demo2").innerHTML = searchResults.response.docs[0].es_description;
let text="";
for(let i=0; i<searchResults.response.docs.length; i++) {
text+="<div class='p-3 border rounded-3'>";
text+="<a href=''>"+ "<strong class='text-primary largeText'>" + searchResults.response.docs[i].es_title + "</strong></a>";
text+="<div class='largeText'>" + searchResults.response.docs[i].es_description + "</div>";
text+="<div>" + searchResults.response.docs[i].author + "</div>";
text+="<div>" + searchResults.response.docs[i].site + "</div>";
text+="<div>" + searchResults.response.docs[i].es_date + "<a class='text-success'> " + searchResults.response.docs[i].site + "</a></div>";
//text+="<a href='url'>"+ searchResults.response.docs[i].es_title + "</a>";
text+="</div>";
//text+=searchResults.response.docs[i].author + "<br>";
//text+=searchResults.response.docs[i].site + "<br>";
//text+=searchResults.response.docs[i].es_date + "<br>";
//text+="<p></p>";
document.getElementById("demo2").innerHTML = text;
console.log(i);
}
//alert(searchResults.response.docs.length);
</script>
demo2 is the id of the div inside of ajax_info and demo is the id of the body of index.html
I have a javascript that reads a xml Phonebook, prints a table and I'd like to make each number clickable so it would launch a Phone App.
<table class="table table-striped table-dark" id="campanie"></table>
function loadXMLDoc() {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
myFunction(this);
}
};
xmlhttp.open("GET", "campanie-full.xml", true);
xmlhttp.send();
}
function myFunction(xml) {
var i;
var xmlDoc = xml.responseXML;
var table="<thead class=thead-light><tr><th><h5 class=text-dark>Nr.</h5></th><th><h5 class=text-dark>Company</h5></th><th><h5 class=text-dark>Phone 1</h5></th><th><h5 class=text-dark>Phone 2</h5></th></tr></thead>";
var x = xmlDoc.getElementsByTagName("DirectoryEntry");
for (i = 0; i <x.length; i++) {
table += "<tr><td><p>" +
[i+1] + "</p></td><td><p>" +
x[i].getElementsByTagName("Name")[0].childNodes[0].nodeValue +
"</p></td><td><a href=tel:>" +
x[i].getElementsByTagName("Telephone")[0].childNodes[0].nodeValue +
"</a></td><td><a href=tel:>" +
x[i].getElementsByTagName("Telephone")[0].childNodes[0].nodeValue +
"</a></td></tr>";
}
document.getElementById("campanie").innerHTML = table;
}
What should I do in order to have each a href=tel: work properly?
Also, you will see that I put the "Telephone" tag twice, as the Phonebook has more than one phonenumber. As a second question, I'd like to know how to make it read correctly, as the XML file can't be edited in any way. The <Telephone> tag from XML can't be changed to <Telephone1> or <Telephone2>. This question can wait, however.
EDIT: I have added an example XML
<CiscoIPPhoneDirectory>
<DirectoryEntry>
<Name>Doctor Dolittle</Name>
<Telephone>100</Telephone>
<Telephone>+19001234567</Telephone>
</DirectoryEntry>
<DirectoryEntry>
<Name>Tommy Stubbins</Name>
<Telephone>101</Telephone>
</DirectoryEntry>
<DirectoryEntry>
<Name>Chee-Chee</Name>
<Telephone>102</Telephone>
</DirectoryEntry>
<DirectoryEntry>
<Name>Prince Bumpo</Name>
<Telephone>103</Telephone>
</DirectoryEntry>
<DirectoryEntry>
<Name>Polynesia</Name>
<Telephone>104</Telephone>
</DirectoryEntry>
<DirectoryEntry>
<Name>Gub-Gub</Name>
<Telephone>105</Telephone>
</DirectoryEntry>
<DirectoryEntry>
<Name>Jip</Name>
<Telephone>106</Telephone>
</DirectoryEntry>
<DirectoryEntry>
<Name>Dab-Dab</Name>
<Telephone>107</Telephone>
</DirectoryEntry>
You'll need to check the Xml to see whether there are 1 or 2 phone numbers. (You could also make it check for none, if that could ever happen, and not add a row at all). Then you add either the 2nd phone number or an empty cell, depending on what the data says.
Change the function that creates the table contents from the Xml response, like this...
function myFunction(xml) {
var i;
var xmlDoc = xml.responseXML;
var table="<thead class=thead-light>" +
"<tr><th><h5 class=text-dark>Nr.</h5></th>" +
"<th><h5 class=text-dark>Company</h5></th>" +
"<th><h5 class=text-dark>Phone 1</h5></th>" +
"<th><h5 class=text-dark>Phone 2</h5></th>" +
"</tr></thead>";
var x = xmlDoc.getElementsByTagName("DirectoryEntry");
for (i = 0; i <x.length; i++) {
var name = x[i].getElementsByTagName("Name")[0].childNodes[0].nodeValue;
var tel1 = x[i].getElementsByTagName("Telephone")[0].childNodes[0].nodeValue;
var tel2 = "";
// if there are 2 phone numbers, get the value of the 2nd one
if (x[i].getElementsByTagName("Telephone").length === 2) {
// check that it's not an empty node...
if (x[i].getElementsByTagName("Telephone")[1].childNodes) {
tel2 = x[i].getElementsByTagName("Telephone")[1].childNodes[0].nodeValue;
}
}
table += "<tr><td><p>" + [i+1] + "</p></td>" +
"<td><p>" + name + "</p></td>" +
"<td><a href='tel:" + tel1 + "'>" + tel1 + "</a></td>";
// if we don't have a 2nd phone number then add an empty cell
if (tel2 === "") {
table += "<td></td>";
}
// if we do have a 2nd phone number then add it
else {
table += "<td><a href='tel:" + tel2 + "'>" + tel2 + "</a></td>";
}
table += "</tr>";
}
document.getElementById("campanie").innerHTML = table;
}
I'm beginner in JS. But, after many hours, i'm really close to the wanted result.
I declare my JS Function in head part
function getPrice(price) {
var tabPrice = price.split("");
var html = "";
var virguleIndex = null;
for (var index = 0; index < tabPrice.length; ++index) {
var priceNumber = tabPrice[index];
if (priceNumber == ',') {
virguleIndex = index;
html += "<span class='p-c'>" + priceNumber + "</span>";
} else if (priceNumber == '-') {
html += "<span class='p-d'>" + priceNumber + "</span>";
} else if (index > virguleIndex && virguleIndex != null) {
html += "<span class='p-" + priceNumber + " p-small'>" + priceNumber + "</span>";
} else {
html += "<span class='p-" + priceNumber + "'>" + priceNumber + "</span>";
}
}
var div = document.getElementsByClassName('price');
div[0].innerHTML = html;
}
and my div in body part
<div class="price"></div>
I made some test - And my function getPrice works perflectly
https://image.noelshack.com/fichiers/2018/02/4/1515663887-functionwork.jpg
Some, the only fail (I think) is that the innerHTML don't work and don't write de var html content in div class price.
I haven't idea yet after many (many) hours of looking.
Can you help me ?
Thanks in advance,
Ludovic
By going through your image it is clear your DOM is not ready. So Please call your function inside this Block.
(function() {
// your page initialization code here
// the DOM will be available here
//Call Your function inside this block. it will work ex. getPrice("100");
})();
Some news (I worked on this few hours), I check for the dom charging. I tried (thank for you answer) the call function / transpose the code and the end / forcing the function after the dom loading (with document.addEventListener("DOMContentLoaded", function(event) {)
Console log still working. But my div still empty :/
Thanks again !
So in my code I created a table pulling from an XML file that displayed two columns of information about plants. The goal of my program is to be able to hover over the first and print out the other information about that plant and print it in another section to the right of my table. The issue is that I am not gettign any console errors and the hover affect is not printing any information.
window.addEventListener("load", link_events);
var xhr = false;
function link_events() {
xhr = new XMLHttpRequest();
if(xhr) {
xhr.addEventListener("readystatechange", ShowFile);
xhr.open("GET", "plants.xml", true);
xhr.send();
} else {
alert("XHR not supported.");
}
}
function ShowFile() {
var i;
var title;
var cover;
var plant_table = "<table><tr><th>Common Name </th><th>Botanical Name </th></tr>";
if (xhr.readyState == 4) {
if (xhr.status == 200) {
//here we have gotten the file correctly
//loop through it and print out cover and title
var plantlist = xhr.responseXML.getElementsByTagName("PLANT");
//booklist is an array and each element is an object sub i
//so you have to use getElementBy something in order to pull the information
for (i = 0; i < plantlist.length; i++) {
var Common = plantlist[i].getElementsByTagName("COMMON")[0].firstChild.textContent;
var Botanical = plantlist[i].getElementsByTagName("BOTANICAL")[0].firstChild.textContent;
plant_table += "<tr>" +
"<td class =\"plant\">" + Common + "</td>" +
"<td>" + Botanical + "</td>" +
"</tr>";
}
plant_table += "</table>";
document.getElementById("outarea").innerHTML = plant_table;
}
var plants = document.getElementsByClassName("plant");
for (i=0; i < plants.length; i++) {
plants[i].onmouseover = HoverChoice;
}
}
function HoverChoice() {
var input = xhr.responseXML.getElementsByTagName("PLANT");
for (i = 0; i < input.length; i++) {
Common = input[i].getElementsByTagName("COMMON")[0].firstChild.textContent;
var Zone = input[i].getElementsByTagName("ZONE")[0].firstChild.textContent;
var Light = input[i].getElementsByTagName("LIGHT")[0].firstChild.textContent;
var Price = input[i].getElementsByTagName("PRICE")[0].firstChild.textContent;
if (plants == this.innerHTML) {
document.getElementById("inarea").innerHTML =
"<h1>" + Common + "</h1>" + "<br />" + "<br />" +
"Zone: " + Zone + "<br />" +
"Light: " + Light + "<br />" +
"Price: " + Price;
}
}
}
}
you could try using addEventListener method instead and see whether it works?
plants.forEach(function(plant){
plant.addEventListener("onmouseover", HoverChoice);
});
or going with the original loop you made it would be
for (i=0; i < plants.length; i++)
{
plants[i].addEventListener("onmouseover", HoverChoice);
}
I'm not anything professional, a common problem I used to encounter in these kinds of event listening functions was that calling a global function sometimes fails but making the function on the spot inside the event listener would work like addEventListener("onmouseover" , function() { return 0; });
Hy everyone! I've got a problem developping a little webapp.
The goal is to search for a specific word in files from a stating folder on the server.
To do that, I've implemented a recursive algorithm using java.io.File and a BufferReader.
When I get the results, I had them in a table using a script in my jsp file :
// Posting founded files in a table.
var files = response.getElementsByTagName("file");
// -> Creating the results table.
var table = "<table width=\"100%\">\n";
for (var i = 0, c = files.length; i < c; i++) {
// -> Building the number of apparence in each file.
var nb = files[i].getAttribute("nb");
var nbSentence = "";
if (nb == 1) { nbSentence = nb + " time in this file."; }
else { nbSentence = nb + " times in this file."; }
// Building and filling the table.
if (i % 2 == 0) { table += "<tr class=\"pair\"><td><a href=" + files[i].firstChild.nodeValue + " target=\"_blank\" >"
+ files[i].getAttribute("name") + "</a></td><td>" + nbSentence + "</td></tr>\n"; }
else { table += "<tr class=\"impair\"><td><a href=" + files[i].firstChild.nodeValue + " target=\"_blank\" >"
+ files[i].getAttribute("name") + "</a></td><td>" + nbSentence + "</td></tr>\n"; }
}
table += "</table>\n";
// -> To end the procedure, we had the table to the right div.
document.getElementById("files").innerHTML = table;
My problem is that with this code, all of the results are printed in one tim in the target table. I would like to see the results comming one by one, everytime a file is found in the algorithm.
I've tried to change the readystate to "3" in the onreadystatestage function :
xhr.onreadystatechange = function() {
if (xhr.readyState >= 3 && (xhr.status == 200 || xhr.status == 0)) {
callback(xhr.responseXML);
document.getElementById("loader").style.display = "none";
document.getElementById("btn").value = "Search";
} else if (xhr.readyState < 3) {
document.getElementById("loader").style.display = "inline";
document.getElementById("btn").value = "Cancel";
}
};
But it doesn't change anything.
Does somebody have an idea? How can I send every founded file one by one ? Do I have t do it in the servlet class ?
The for instruction in the servlet class :
// If the input word name isn't empty, the algorithm is launched.
if (null != wordToSearch && !"".equals(wordToSearch))
{
lstFiles.clear();
searching(new File(contextPath), wordToSearch);
int n = lstFiles.size();
// Priting a message that indicate how many files have been found with the word to search.
emptyFieldMessage = n + " files has been found containing the word '" + wordToSearch + "'!";
output.append("<message>").append(emptyFieldMessage).append("</message>\n");
output.append("<lstFiles>\n");
// Then, files list with :
// - File path in "name" parameter,
// - Number of apparence of the word in "nb" parameter,
// - Formatted path as the value.
for(int i = 0; i < n; i++)
{
output.append("<file name=\"" + lstFiles.get(i) + "\" nb=\"" + lstNbApparence.get(i) + "\" >").append(lstFilesPath.get(i)).append("</file>\n");
}
output.append("</lstFiles>\n");
}
To be more complet, the whole script code :
<script>
// Creating xhr variable.
var xhr = null;
// Creating the "Search" button function.
function request(callback) {
// "Cancel" button case.
if (xhr && xhr.readyState != 0)
{
xhr.abort();
}
// "Search" button case.
else
{
// Calling the good function from external file.
xhr = getXMLHttpRequest();
// Callback and loading icon management.
xhr.onreadystatechange = function() {
if (xhr.readyState >= 3 && (xhr.status == 200 || xhr.status == 0)) {
callback(xhr.responseXML);
document.getElementById("loader").style.display = "none";
document.getElementById("btn").value = "Search";
} else if (xhr.readyState < 3) {
document.getElementById("loader").style.display = "inline";
document.getElementById("btn").value = "Cancel";
}
};
// Calling the Servlet in charge of the recursion algorithm.
var input = encodeURIComponent(document.getElementById("wordName").value);
xhr.open("GET", "/webApp_Search_Merge/ActionServlet?wordName=" + input, true);
xhr.send(null);
}
}
// Creating the reponse function.
function readData(response) {
if (null != response)
{
// Posting the message include in the XML file sending back by the Servlet.
var message = response.getElementsByTagName("message");
document.getElementById("message").innerHTML = message[0].firstChild.nodeValue;
// Posting founded files in a table.
var files = response.getElementsByTagName("file");
// -> Creating the results table.
var table = "<table width=\"100%\">\n";
for (var i = 0, c = files.length; i < c; i++) {
// -> Building the number of apparence in each file.
var nb = files[i].getAttribute("nb");
var nbSentence = "";
if (nb == 1) { nbSentence = nb + " time in this file."; }
else { nbSentence = nb + " times in this file."; }
// Building and filling the table.
if (i % 2 == 0) { table += "<tr class=\"pair\"><td><a href=" + files[i].firstChild.nodeValue + " target=\"_blank\" >"
+ files[i].getAttribute("name") + "</a></td><td>" + nbSentence + "</td></tr>\n"; }
else { table += "<tr class=\"impair\"><td><a href=" + files[i].firstChild.nodeValue + " target=\"_blank\" >"
+ files[i].getAttribute("name") + "</a></td><td>" + nbSentence + "</td></tr>\n"; }
}
table += "</table>\n";
// -> To end the procedure, we had the table to the right div.
document.getElementById("files").innerHTML = table;
}
}
Thanks by advance for your help, Thomas.
I tried to set up a working demo, but with no results. I was also searching why I can't find the way to "sleep" a function and re-execute after 1000 milliseconds or whatever you want. Already found an answer to that, but I think it's not really what did you expected:
A sleep function will kill the browser and possibly the machine.
Javascript is single threaded, so the browser will block while this
executes, and the loop itself will just take up a lot of CPU. I’ve
heard of some libraries that actually do sleep correctly in an
asynchronous manner, but I can’t remember the name right now.
This is a very bad idea. JavaScript is single threaded so while that
for loop is running nothing else can execute (js timers, browser
events, even the UI in most browsers). Try to sleep for 5 or more
seconds and the browser will even warn the user that a script is
running slowly.
Just use setTimeout.
Also speaks about a sleep function into Native Javascript. It seems that it's like a framework or something like that. You can download it and try it at your own. I can't say anything about this because I've never tested, it's just what I found on internet.
I'm sorry to give you bad news.