Javascript DOM errors - javascript

this is my javascript code , I am trying to create a dynamic list in HTML with data I recieve from the server , The data is of type "json"
My Javascript snippet
function addBooks(data) { // USing DOM to populate the tables
//var newdata=document.getElementById('addBooks');
//newdata.setattribute()
//get the unordered list
var newdata = document.getElementById('addBooks');
var parent = document.getElementById('gBookList');
//removeChildrenFromNode(parent);
//create list divider
var listdiv = document.createElement('li');
listdiv.setAttribute('id', 'gBookListDiv');
listdiv.innerHTML = ("Books Found:");
parent.appendChild(listdiv);
// (this is where the first error happens)
//create dynamic list
for (i = 0; i < data.length; i++) {
// (this is where the second error happens)
//create each list item
var listItem = document.createElement('li');
listItem.setAttribute('id', 'gBookListItem');
parent.appendChild(listItem);
//var link = document.createElement('a');
//link.setAttribute('onclick','displayBook(data[i])');
//link.setAttribute('href','#FindBook)');
//listItem.appendChild(link);
var pic = document.createElement('img');
pic.setAttribute('src', data[i].pictureURL);
pic.setAttribute('width', '80px');
pic.setAttribute('height', '100px');
pic.setAttribute('style', 'padding-left: 10px');
link.appendChild(pic);
var brk = document.createElement('br')
link.appendChild(brk);
var title = document.createElement('p');
title.innerHTML = data[i].title;
title.setAttribute = ('style', 'float:right');
link.appendChild(title);
var author = document.createElement('p');
author.innerHTML = data[i].author;
link.appendChild(author);
}
var list = document.getElementById('gBookList');
// $(list).listview("refresh");
}
/*function removeChildrenFromNode(node){
while (node.hasChildNodes()){
node.removeChild(node.firstChild);
}
//}*/
My html code is
<!DOCTYPE html>
<head>
<script ...>
<head>
<body onLoad="addBooks()">
<div id="addBooks" class="row-fluid">
<div id="gBookList">
</div>
</div>
</body>
</html>
I keep getting the following error which prevents me from populating the list , I am using chrome
1) Uncaught TypeError: Cannot call method 'appendChild' of null
2) Uncaught TypeError: Cannot read property 'length' of undefined
I do not understand why this should happen as the .length commands returns the correct integer ( amount of json objects) when I debug using a alert box .
the function that calls it
$.ajax({
type: 'GET',
url: ........,
dataType: "json",
complete: function (xhr, statusText) {
alert(xhr.status);
},
success: function (data, textStatus, jqXHR) {
alert(JSON.stringify(data));
window.location.replace("Page2_updated.html");
addBooks(data); // Passing JSON to be replaced on page
},
function (data, textStatus, jqXHR) {
alert(data);
alert('error');
},
});
Edit
I changed my HTML file to the following structure after advice on this forum
<html>
<head>
</head>
<body>
<div id="1" "display:block">
</div>
<div id="2" "display:none"> // no onLoad() anymore!!
</div>
</body>
</html>
I have edited this part int he calling function
$.ajax({
type: 'GET',
url: ........,
dataType: "json",
complete: function (xhr, statusText) {
alert(xhr.status);
},
success: function (data, textStatus, jqXHR) {
alert(JSON.stringify(data));
if(document.getElementById(1).style.display == "block"){
document.getElementById(1).style.display = "none";
document.getElementById(2).style.display = "block"; }
addBooks(data); // Passing JSON to be replaced on page
},
function (data, textStatus, jqXHR) {
alert(data);
alert('error');
},
});
But I still get the following errors
Uncaught TypeError: Cannot call method 'appendChild' of null
Uncaught TypeError: Cannot read property 'length' of undefined

Here is a working version of your code that builds a list. Compare with your version to see where you made the mistakes, in both mark up and code.
The source of your second error is incorrect data (most likely null) being passed to the addBooks function, so you would have to fix that.
Chrome and Firebug have excellent JavaScript debuggers with breakpoints, so use that to your advantage to identify the issues:
http://jsfiddle.net/tgth2/
EDIT:
Your problem is gleamingly obvious, after your comments and updates to the question:
Your first page is loading the JSON data from the service, but then does window.location.replace("Page2 Updated.html");, which sends the browser to the new page (notice that you're calling addBooks(data); immediately after. But that code is never executed because browser has already gone to another page
Your second page has <body onload="addBooks();"> in it, which will cause the function to be called with a null data. This is the cause of your problem.
SOLUTION:
Number one suggestion would be to start using jQuery for everything else you're doing, and not just for the AJAX call.
Secondly, you should have the ajax call and the results rendering in one page, as it does not make any sense to redirect the browser to another page. Because your javascript always works in the context of a single page. As soon as you do something like window.location.replace(..) you end up losing everything you've done in the current page.
If you make these changes, you will see that your list loads just fine!

This line in your loop creates multiple list items with the same ID:
listItem.setAttribute('id','gBookListItem');
try removing it - i don't think you need it.

That's an error :
title.setAttribute=('style','float:right');
do:
var title = document.createElement('p');
title.innerHTML = data[i].title;
title.style.cssFloat = 'right';
link.appendChild(title);
and
var pic = document.createElement('img');
pic.src = data[i].pictureURL;
pic.width = '80px';
pic.height = '100px';
pic.style.paddingLeft = '10px';
link.appendChild(pic);
etc......

Any chance that you're accidentally calling addBooks() somewhere in your code without any data?

I tried to cut it down to the barebones and I'm pretty sure the fact that link is undefined is the reason you get an error when you call appendChild. It's certainly the first error I found in the console in Firebug. The following barebones sequence works in Firefox (sorry I don't have Chrome):
var json =[
{"pictureURL":"/test1.jpg/","title":"test1"},
{"pictureURL":"/test2.jpg/", "title":"test2"},
{"pictureURL":"/test3.jpg", "title":"test3"}
];
function displayBook(title){
alert(title);
return false;
}
function addBooks(data) {
var newdata=document.getElementById('addBooks');
var parent = document.getElementById('gBookList');
var listdiv = document.createElement('li');
listdiv.id = 'gBookListDiv';
listdiv.innerHTML = "Books Found:";
parent.appendChild(listdiv);
for(var i=0;i<data.length;i++){
var listItem = document.createElement('li');
listItem.id = 'gBookListItem-' + i;
parent.appendChild(listItem);
var link = document.createElement('a');
link.id = listItem.id + "-link";
link.href = '#FindBook';
link.innerHTML = data[i].title;
listItem.appendChild(link);
link.setAttribute("onclick", "return displayBook('" + data[i].title + "');");
var pic = document.createElement('img');
pic.src = data[i].pictureURL;
}
var list = document.getElementById('gBookList');
}
I discovered from this answer JavaScript: changing the value of onclick with or without jQuery that I had to use setAttribute to add the onclick handler. I'm used to adding other attributes like id directly as mentioned by adeneo without calling setAttribute.

Related

How to change the content of a JavaScript function dynamically?

The problem I have is that I am trying to change the image from a canvas tag when the client selects a different radio button.
The content of the canvas is stored in the database with the code of the draw which I got from Illustrator (a lot of code).
What I did first was to change the data from a script tag by id where I created the function that paints the canvas.
It worked well, it painted the draw correctly. The problem is that when I select another radio button, even when the content of the script changes and so does the function, it draws the same painting and not the updated one.
I think that this happens because JavaScript does not update the content of the function after this has been already called once. Am I wrong?
If it is the problem I have, is it possible to change the content of the function after it has been called?
This is the html code:
<canvas id="myCanvasDel" height="600" width="600" style="max-width:600px;"></canvas>
<script id="scriptjs"></script>
This is the JavaScript one when I click on the radio button:
function mostrarCanvas(codiprd, codicol) {
$.ajax({
dataType: "html",
type: "POST",
url: "ajaxcanvas.php",
data: {
codiprd: codiprd,
codicol: codicol
},
success: function (datos) {
$('#scriptjs').html(datos);
var canvasDel = document.getElementById("myCanvasDel");
var ctxDel = canvasDel.getContext("2d");
drawDel(ctxDel);
},
error: function (e) {
alert('Ha habido un error: ' + e);
}
});
return false;
}
And this is the PHP that the ajax file calls:
$codiprd=$_POST['codiprd'];
$codicol=$_POST['codicol'];
$querycnv = "SELECT CANVAS "
. "FROM MYTABLE PC "
. "WHERE PC.CODIPRD=$codiprd AND PC.CODICOL=$codicol "
. "GROUP BY PC.CODIPRD,PC.CODICOL;";
$resultcnv = mysqli_query($conn, $querycnv)or die(mysqli_error());
$canvas = mysqli_fetch_array($resultcnv);
echo $canvas['CANVAS']);
You can redefine the function as you can redefine any varible.
function foo(){
console.log("blah");
}
can be redefined with
foo = function(){
console.log("blah,blah");
}
A function is just another object, and thus can be used like any referenced variable.
You can create a function from a string
var funcStr = 'return "hi there!";'; // the function body
var func = new Function(funcStr); // create the function
console.log(func()); // >> hi there
You set arguments with
var funcStr = 'return "hi there " + name;'; // the function body with arg name
var func = new Function("name",funcStr); // create the function with the argument name
console.log(func("Me")); // >> hi there Me
You can also create a script tag and add it to the DOM
var scriptSource = "//Source code;\nconsole.log("Script run");"
var script = document.createElement("script");
script.async = true;
script.text = scriptSource;
document.body.appendChild(script);
// in time the console will read
// >> Script run
You need to wait for the script to be parsed which will not happen until you exit the current execution. After the script has loaded, it is first parsed and then run. If you wish you can just have the function body in the script tag and let it run by itself.

Assigning javascript variable to java variable

I know I can't use javascript variable inside java code so can anyone explain me what I can do instead?
function init(srcc) {
<%if (session.getAttribute("status") != null && session.getAttribute("status").equals("member")) {%>
alert(srcc + " ");
<%application.setAttribute(session.getAttribute("currentuser"), srcc);%>
<%}%>
in this line:
<%application.setAttribute(session.getAttribute("currentuser"), srcc);%>
I can't read the srcc variable as it's assigned in javascript, this function called when I press a button in jquery, code:
var $lightbox = $("<div class='lightbox'></div>");
var $img = $("<img>");
var $caption = $("<p class='caption'></p>");
var $btn = $("<div align='center'> <INPUT TYPE='BUTTON' VALUE='Add to cart'></div>");
$lightbox.append($img).append($caption).append($btn);
$('body').append($lightbox);
$('.gallery li').click(function(e) {
e.preventDefault();
var src = $(this).children('img').attr("src");
var cap = $(this).children('img').attr("alt");
$btn.off('click').on('click', function(da) {
$(document).ready(function() {
init(src);
});
});
$img.attr('src', src);
$caption.text(cap);
$lightbox.fadeIn('fast');
$lightbox.click(function() {
$lightbox.fadeOut('fast');
});
});
I use it in an "add to cart" button, I want the server to keep data of whom added it to the cart and what he added. (srcc equals what he added and session.getAttribute("currentuser") is whom added).
Thanks guys.
You can send that JavaScript variable to Java using an AJAX request
You would have to have a serverside route set up to handle this request coming in and process the sent data.
Since I already see jQuery being used in your code, I'll use this AJAX function in my example code. You can send an HTTP request without your browser reloading the page in this way:
$.get("/urlOfCartHandler/?parameterName=" + javaScriptVariableContainingDataYouWantToSend, function(data) {
//Request was a success
}).fail(function() {
//Request failed
});

problems displaying page, deleting contents and repopulating - could this be multiple binding?

I have a mobile app.
It consists of 2 screens. The first is for capturing user
credentials and the 2nd is for displaying data.
The idea is to collect the credentials on screen 1.
Then make an ajax call with the credentials to get data and present it on
screen 2 as a series of links.
Then allow the user to touch a link on screen 2. This will return the link data to the javascript and pass it to the ajax call and get more data - THEN delete all the data on screen 2 and repopulate it with the new data.
First thing I want to find out: is showing a page with mobile.changePage(), populating it, deleting the contents and then repopulating it (without another call to mobile.changePage()) a reasonable thing to do?
I'm having a problem and I think its related to how I'm using onclick in the <a>
Each time I display the most recently received data, I want to display it in an <a>. I write each onclick to call the getData routine passing it information to determine the next ajax AND whatever is being displayed in the <a>. The only way I could figure out to access that was in onclick.
Is there a better way?
I'm able to display the results of the first ajax call just fine. But things get weird with the 2nd, 3rd etc.
Sometimes I'll touch a link and I'll progress thru the screens as I expect.
Sometimes I'll touch an <a> on the 1st result screen, the 2nd result screen will display and then (without me selecting data from the 2nd screen) the 3rd screen will display.
I've looked at the logs and the getData() routine is being executed.
What could be causing this? Am I somehow not destroying all the <a> properly? Am I using onclick in a fashion its not designed for? Should I be using buttons styled to look like links instead of <a>
Here's my code:
"use strict";
var app = {
onDeviceReady: function() {
$('#startButton').click(function(){
app.getDeptsForUser();
});
},
getDeptsForUser: function(){
var parms = new Object();
parms.userName = assignedUser;
app.getData(JSON.stringify(parms),"ENDPOINT1", "Departments");
$.mobile.changePage("#index", { transition: 'slide' });
},
getData: function(paramStr, endpoint, displayHeader){
var paramStrObj = JSON.parse(paramStr);
var serverName = server + ":" + port;
var encoded = Base64().encode(paramStrObj.userName + ':' + pass);
var authType = 'Basic ' + encoded;
var option = endpoint+"?action=start&params=" + paramStr;
var URL = serverName + "/rest/bpm/wle/v1/service/"+option;
$.ajax({
url: URL,
type: "POST",
crossDomain: true,
jsonp: "callback",
beforeSend: function (xhr) {
xhr.setRequestHeader("Authorization", authType);
},
success: function (result) {
console.log("MobileMockUp getData() ajax success result="+JSON.stringify(result));
if (endpoint === "ENDPOINT1"){
app.displayData(paramStr, endpoint,"Departments", result.data.data.depts.items);
}
else if (endpoint === "ENDPOINT2"){
app.displayData(paramStr, endpoint,displayHeader, result.data.data.checklists.items);
}
else if (endpoint === "ENDPOINT3"){
app.displayData(paramStr, endpoint,displayHeader, result.data.data.checks.items);
}
},
error: function(jqXHR, textStatus, errorThrown) {
alert('Unable to retrieve '+displayHeader);
},
});
},
displayData: function(currParms,currEndPt, headerText, list){
var nextEndpt;
var nextHeaderText;
var currParmsObj = JSON.parse(currParms);
if (currEndPt === "MD#getDeptsForUser"){
nextEndpt = "MD#getCheckLists";
nextHeaderText = "Check Lists";
}
else if (currEndPt === "MD#getCheckLists"){
nextEndpt = "MD#getChecks";
}
var htmlListString="";
var parmObj;
var newLink;
$('#headerText').text(headerText);
for (var i = 0; i < list.length; i++){
parmObj = new Object();
if (currEndPt === "ENDPOINT1"){
parmObj.userName=currParmsObj.userName;
parmObj.dept=list[i];
}
else if (currEndPt === "ENDPOINT2"){
parmObj.userName=currParmsObj.userName;
parmObj.dept=currParmsObj.dept;
parmObj.checklist=list[i];
}
else if (currEndPt === "ENDPOINT3"){
nextHeaderText = list[i];
}
var str = JSON.stringify(parmObj);
str = str.toString().replace(/"/g, '\\"');
newLink = "<a style='background:#ffffff;padding-top:5%;border-top: thin solid black; display:block;font-size:12px;font-weight:normal;color:#000000;text-decoration: none;' href='#' onclick='app.getData(\""+str+"\",\""+nextEndpt+"\",\""+nextHeaderText+"\")'><pre>" + list[i] + " </pre></a><br>";
htmlListString=htmlListString+newLink;
}
$('#taskListUL').empty();
$('#taskListUL').append(htmlListString);
}
};
Could this be multiple binding?
i figured out it was multiple bindings

JSON data passing between html pages [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Javascript DOM errors
I have my following html code:
<html>
<head>
</head>
<body>
<div id="1" "display:block">
</div>
<div id="2" "display:none"> // no onLoad() anymore!!
</div>
</body>
</html>
My JavaScript code is as follows:
$.ajax({
type: 'GET',
url: ........,
dataType: "json",
complete: function (xhr, statusText) {
alert(xhr.status);
},
success: function (data, textStatus, jqXHR) {
alert(JSON.stringify(data));
if(document.getElementById(1).style.display == "block"){
document.getElementById(1).style.display = "none";
document.getElementById(2).style.display = "block"; }
addBooks(data); // Passing JSON to be replaced on page
},
function (data, textStatus, jqXHR) {
alert(data);
alert('error');
},
});
function addBooks(data) { // USing DOM to populate the tables
//var newdata=document.getElementById('addBooks');
//newdata.setattribute()
//get the unordered list
var newdata = document.getElementById('addBooks');
var parent = document.getElementById('gBookList');
//removeChildrenFromNode(parent);
//create list divider
var listdiv = document.createElement('li');
listdiv.setAttribute('id', 'gBookListDiv');
listdiv.innerHTML = ("Books Found:");
parent.appendChild(listdiv);
// (this is where the first error happens)
//create dynamic list
for (i = 0; i < data.length; i++) {
// (this is where the second error happens)
//create each list item
var listItem = document.createElement('li');
listItem.setAttribute('id', 'gBookListItem');
parent.appendChild(listItem);
//var link = document.createElement('a');
//link.setAttribute('onclick','displayBook(data[i])');
//link.setAttribute('href','#FindBook)');
//listItem.appendChild(link);
var pic = document.createElement('img');
pic.setAttribute('src', data[i].pictureURL);
pic.setAttribute('width', '80px');
pic.setAttribute('height', '100px');
pic.setAttribute('style', 'padding-left: 10px');
link.appendChild(pic);
var brk = document.createElement('br')
link.appendChild(brk);
var title = document.createElement('p');
title.innerHTML = data[i].title;
title.setAttribute = ('style', 'float:right');
link.appendChild(title);
var author = document.createElement('p');
author.innerHTML = data[i].author;
link.appendChild(author);
}
var list = document.getElementById('gBookList');
// $(list).listview("refresh");
}
/*function removeChildrenFromNode(node){
while (node.hasChildNodes()){
node.removeChild(node.firstChild);
}
//}*/
I keep getting the following error which prevents me from populating the list , I am using Chrome
Uncaught TypeError: Cannot call method 'appendChild' of null
Uncaught TypeError: Cannot read property 'length' of undefined
I have posted this question yesterday, but I just wanted a fresh perspective on what the error could be.
There could be a few issues here :-
Are you doing this cross domain? If you are consider using JSONP instead which will solve some of the issues you may be seeing with data being "withheld" due to security policies.
You are also accessing a varible and making a assumption it has a value
var parent = document.getElementById('gBookList');
Before you use the parent tag, you should ensure that its not null (or a empty reference) and that the element (gBookList) does infact exist in your document.
must uncomment
// var link = document.createElement('a');
in
link.appendChild(pic);
this element is not decalred yet (in your case is just commented)!

Parsing XML JQuery Ajax Response with Namespace

I'm executing a web service call using JQuery and it's ajax function and I'm unable to parse the data coming back. When I alert the data (alert($(data).find("return").text()) its empty. I see the server responding with xml data as outlined below and when I alert(data) I get [object XMLDocument]. Is txt = $(data).find("return").text() valid given my XML structure with a namespace below? I can see the full xml string in firebug. Any ideas?
var txt = $(data).find("ns1\:return").text(); works on Chrome and Firefox, but not Safari
index.js:
$(function () {
$.ajax({
url: url,
success: function (data) {
var ndx = 0,
row,
**txt = $(data).find("return").text(),**
xml = unescape(txt),
xmlDoc = $.parseXML(xml),
firstrow = $(xmlDoc).find(
"results").children(":first");
// populate the table based on the results returned by
// the web service
$("table.results thead").empty();
$("table.results tbody").empty();
row = $("<tr/>");
row.append($("<th/>").text("#").addClass("ndx"));
firstrow.children().each(function () {
row.append($("<th/>").text(this.nodeName));
});
row.appendTo($("table.results thead"));
$(xmlDoc).find("row").each(function () {
row = $("<tr/>");
row.append($("<td/>").text(ndx + 1).addClass("ndx"));
$(this).children().each(function () {
row.append($("<td/>").text($(this).text()));
});
row.appendTo($("table.results tbody"));
ndx++;
});
// clear the table if no results were returned
if (ndx == 0) {
// no rows returned
$("table.results thead").empty();
$("table.results tbody").empty();
}
statusNotice("Records Returned: " + ndx);
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
// display the error returned by the web service
var xmlDoc = $(XMLHttpRequest.responseXML);
statusError(xmlDoc.find("Text").text());
},
complete: function(XMLHttpRequest, textStatus) {
// hide the busy dialog
$("#busy-dlg").dialog("close");
}
});
});
index.html:
Demo
<script type="text/javascript" src="js/jquery-1.6.4.min.js"></script>
<script type="text/javascript" src="js/jquery-ui-min.js"></script>
<script type="text/javascript" src="js/jquery.layout-latest.js"></script>
<script type="text/javascript" src="js/index.js"></script>
</head>
<body>
//table displaying results from ajax call here
</body>
</html>
XML:
<ns1:executeResponse xmlns:ns1="http://sqlws.test.com">
<ns1:return>
<results>
<row>
<attribute1>value1</attribute1>
<attribute2>value2</attribute2>
</row>
<row>
<attribute1>value1</attribute1>
<attribute2>value2</attribute2>
</row>
</results>
</ns1:return>
</ns1:executeResponse>
When an element is prefixed by a namespace, you have to also add the namespace:
.find('ns1:return') does not work, because : is used by jQuery as pseudo-selectors.
.find('ns1\:return') does not work either, because a single backslash in a string is used as an escape character. "ns1\:return" becomes "ns1:return" which is equal to the previous one.
.find('ns1\\:return') should be used. The double backslash is used to escape the colon.
It appears that the last solution works fine in IE and Firefox, but not Opera, Chrome or Safari. To get maximum compatibility, use jQuery selectors with, and without fake prefix, ie. "ns1\\:return, return" instead of a plain ns1\\:return.
Demo: http://jsfiddle.net/5BQjv/51/
// For example, this is the result:
var data = '<ns1:executeResponse xmlns:ns1="http://sqlws.test.com">' +
'<ns1:return>' +
'<results> <row> ... </row> </results>' +
'</ns1:return>' +
'</ns1:executeResponse>';
// The very first thing is to parse the string as XML. NOT later!
var $xmlDoc = $($.parseXML(data));
// Then, look for the element with the namespace:
var $txt = $xmlDoc.find('ns1\\:return, return');
// No need to use unescape or something, just use DOM manipulation:
// `results` is the immediate child. Don't use .find, but .children
var $firstrow = $txt.children("results").children(":first");
As you may have noticed, I have prefixed some variables with a dollar sign. It's the convention to prefix variables which refer to jQuery objects with a dollar sign, to avoid confusion during/after development.

Categories