I have installed in my project django-contib-comments and I have an HTML that displays the list of comments and also displays the form to enter a new one.
I now want to use Ajax to submit the form without a page refresh and on success to add the submitted comment to the list.
I have done most of the work, but I'm sure there must be an easier way to achieve this.
my question is if there is a way for me to render a Django HTML tag within a javascript something like this:
document.getElementById("comments").innerHTML = {% render_comment_list for obj %}
so far this is the code I have done:
1) I don't want to change anything in the django-contrib-comments project (i am avoiding to override methods.
2) I used the standard tags in django-contrib-comments to render a list of comments.
{% render_comment_list for obj %}
3) Created a JavaScript that handles the submit of the form and then creates a new entry in the list.
function submit_comments(event) {
event.stopPropagation();
$.ajax({
type: $('#comment_form').attr('method'),
url: $('#comment_form').attr('action'),
data: $('#comment_form').serialize(),
cache: false,
dataType: "html",
success: function (html, textStatus) {
var comment_count_btn = document.getElementById('comment-text-vertical-btn');
if (comment_count_btn != null) {
if (!isNaN(parseInt(comment_count_btn.innerHTML))) {
comment_count_btn.innerHTML = parseInt(comment_count_btn.innerHTML) + 1 + " Comments";
}
}
var comment_count_head = document.getElementById('kapua-comments-header');
if (comment_count_head != null) {
if (!isNaN(parseInt(comment_count_head.innerHTML))) {
comment_count_head.innerHTML = parseInt(comment_count_head.innerHTML) + 1 + " Comments:";
}
}
if (document.getElementById("comments") != null){
submitted_timestamp = getQueryParameter("timestamp", this.data);
submitted_date = new Date();
if (submitted_timestamp == null) {
submitted_date = new Date(submitted_timestamp);
}
submitted_comment = getQueryParameter("comment", this.data);
if (submitted_comment == null) {
submitted_comment = "No value entered"
}
html_comment = "<div class=\"right-aligned\"><div class=\"comment-date\">" + submitted_date + " - " + "</div>" + submitted_comment + "</div><br><br>";
current_html = document.getElementById("comments").innerHTML;
document.getElementById("comments").innerHTML = html_comment + current_html;
}
if (document.getElementById("comment_form") != null){
document.getElementById("comment_form").reset();
}
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
$('#comment_form').replaceWith('Your comment was unable to be posted at this time. We apologise for the inconvenience.');
}
});
return false;
};
Thanks in Advance
Yes there is way in django, You can use [escape][1] to render HTML tag. Here is an simple example -
from django.utils.html import escape
def example(request):
return "%s<div><i>%s</i></div>" % (escape(text), escape(other_text)
For more explanation you can refer to documentation.
https://docs.djangoproject.com/en/2.1/ref/utils/#django.utils.html.escape
Still have any doubts comment it out.
I really really need your help pls. I have been battling with these for days and my project is stucked. Your help will really be appreciated.
I have 3 pages.
Page one receives my data, and html formatted version is created. it is a loop and it returns 10 posts.
===
page 2 is the html page that displays the 10 post
====
page 3. the posts at page 2 are just featured image and excerpt and title with url... to read full, click it and go to page 3 ...
Page 3 uses the unique id of each posts to display the full post:
my question: how do i pass each post id to page 3 for full content view.
i tried to store the id generated in page 1 to localstorage, but bcos its a loop ... ONLY THE LAST ONE IS STORED..
my code..
Page 1 - script page receives data
document.addEventListener("deviceready", onDeviceReady, false);
var portfolioPostsContainer = document.getElementById("portfolio-posts-container");
function onDeviceReady(){
var ourRequest = new XMLHttpRequest();
ourRequest.open('GET', 'http://myurl/wp-json/wp/v2/posts?_embed');
ourRequest.onload = function() {
if (ourRequest.status >= 200 && ourRequest.status < 400) {
var data = JSON.parse(ourRequest.responseText);
createHTML(data);
console.log(data);
} else {
console.log("We connected to the server, but it returned an error.");
}
};
ourRequest.onerror = function() {
console.log("Connection error");
};
ourRequest.send();
}
Page 1 still: CreateHTMl create thru a loop
function createHTML(postsData) {
var ourHTMLString = '';
for (i = 0; i < 1; i++)
{
var posturl = postsData.link
ourHTMLString +='<tr>';
ourHTMLString += '<td>' + '' + postsData[i].title.rendered + ''+'</td>';
ourHTMLString += '<td>' + '<img width="100%" src ="' + postsData[i]._embedded['wp:featuredmedia']['0'].source_url + '" />' + ''+'</td>';
ourHTMLString += '<td>' + postsData[i].excerpt.rendered + localStorage.setItem("postid",postsData[i].id)+'</td>';
//i tried to store each id in a localstorage but only the last one remains
ourHTMLString+= '</tr>';
} portfolioPostsContainer.innerHTML = ourHTMLString;
}
page two uses this to display ourHTMLString
<div id="portfolio-posts-container"></div>
page 3 Need each post id.
function onDeviceReady(){
var ourRequest = new XMLHttpRequest();
ourRequest.open('GET', 'http://myurl/wp-json/wp/v2/posts/'+mypostid+'?_embed=true')
ourRequest.onload = function() {
if (ourRequest.status >= 200 && ourRequest.status < 400) {
var data = JSON.parse(ourRequest.responseText);
// createHTML(data); '+mypostid)
console.log(data);
var ourHTMLString = '';
Each post has its generated id from the api, how do i pass it to page 3 for displaying individual post
Although I'm a little confused as re the overall structure of this system, you could pass the id as a query string parameter.
View post 123
This can be parsed using location.search within JavaScript:
var postMatch = /id=(\d+)/.exec(location.search);
if(postMatch) {
var postId = postMatch[1];
// Load post postId...
} else {
// No post was passed
}
I have used the Asp.Net Identity framework in my app.There is a need, when the session expires give a prompt message, and then jump to the login page instead of directly jump to the login page.Prompt information using custom styles.
Because my app's left menus load the view with ajax,so I overried the AuthorizeAttribute.HandleUnauthorizedRequest methord to return a json.Now when users click left menus, it can work properly.But if users refresh the page by click F5,the page will still jump directly to the login page.
I have already overrided AuthorizeAttribute.HandleUnauthorizedRequest
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
var httpContext = filterContext.HttpContext;
string sintab = httpContext.Request["inTab"];
if (!string.IsNullOrEmpty(sintab) && bool.Parse(sintab))
{
var result = new JsonResult();
result.Data = new
{
Authorize = false,
Url = LOGIN_URL
};
result.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
filterContext.Result =result;
return;
}
if (filterContext.Controller.GetType() != typeof(Controllers.HomeController) &&
!filterContext.ActionDescriptor.ActionName.Equals("Index", StringComparison.OrdinalIgnoreCase))
{
string returnUrl = "/" + filterContext.Controller.GetType().Name.Replace("Controller","") + "/Index" ;
returnUrl = httpContext.Server.UrlEncode(returnUrl);
httpContext.Response.Redirect("~/Account/Login?ReturnUrl="+returnUrl);
return;
}
base.HandleUnauthorizedRequest(filterContext);
}
The code of left menus' loadView js
$.get(url, null, function (html) {
html = html.replace(/#%/g, "\"").replace(/%#/g, "\"");
var json;
try {
json = eval("(" + html + ")");
} catch (e) {
}
if (json && !json.Authorize) {
// give an message
layer.alert("Session timeout, please re login.", function (index) {
window.location.href = json.Url + "?returnurl=" + encodeURI(hash);
});
}
else {
$("#content").empty().html(html);
_initModalButton();
$("#content").show();
}
}, 'html');
The page looks like this image
I want to know if there are some better ways to do this because there are a lot of other button need to check authorize status and show message before jump to the login page,and how to give the message when users refresh the page?
Thanks very much!
I think you're looking for are Global Ajax Events.
Please, check this, I think this make your job easier.
I'm trying to get the transposh plugin to translate everytime the cart is updated dynamically. Currently, the plugin will translate and then woocommerce would update the cart thus the translations disappear.
I found the following code in WooCommerce's checkout.js:
// Event for updating the checkout
$('body').bind('update_checkout', function() {
clearTimeout(updateTimer);
update_checkout();
});
I believe this is the code (I can only find the minified version of it) for how transposh gets the translations going in transposh.js:
(function(c){function D(b,a){if(0!==c.trim(a).length){var d=function(){var b=c(this).attr("id").substr(c(this).attr("id").lastIndexOf("_")+1),a=c("#"+e+"img_"+b);c("#"+e+b).attr("data-source",1);a.removeClass("tr-icon-yellow").removeClass("tr-icon-green").addClass("tr-icon-yellow")};c("*[data-token='"+b+"'][data-hidden!='y']").html(a).each(d);c("*[data-token='"+b+"'][data-hidden='y']").attr("data-trans",a).each(d)}}function E(b,a){clearTimeout(v);h.push(b);r.push(a);D(b,a);v=setTimeout(function(){var b=
{ln0:t_jp.lang,sr0:s,action:"tp_translation",items:h.length},a;for(a=0;a<h.length;a+=1)b["tk"+a]=h[a],b["tr"+a]=r[a],t+=c("*[data-token='"+h[a]+"']").size();c.ajax({type:"POST",url:t_jp.ajaxurl,data:b,success:function(){var b=t/k*100;t_jp.progress&&c("#"+m).progressbar("value",b)}});r=[];h=[]},200)}function l(b,a){E(b,c("<div>"+c.trim(a)+"</div>").text());var d=(k-c("."+e+'[data-source=""]').size())/k*100;t_jp.progress&&c("#"+n).progressbar("value",d)}function w(b,a,d){c.ajax({url:t_jp.ajaxurl,dataType:"json",
type:"GET",data:{action:"tp_gp",tl:d,q:b},success:a})}function x(b,a){w(a,function(a){c(a.results).each(function(a){l(b[a],this)})},t_jp.lang)}function y(b,a,d){c.ajax({url:"https://www.googleapis.com/language/translate/v2",dataType:"jsonp",data:{key:t_jp.google_key,q:b,target:d,source:t_jp.olang},traditional:!0,success:a})}function F(b,a){y(a,function(d){"undefined"!==typeof d.error?x(b,a):c(d.data.translations).each(function(a){l(b[a],this.translatedText)})},t_jp.lang)}function p(b,a,d){if(t_jp.msn_key){var f=
"[";c(b).each(function(a){f+='"'+encodeURIComponent(b[a].replace(/[\\"]/g,"\\$&").replace(/(\r\n|\n|\r)/gm," "))+'",'});f=f.slice(0,-1)+"]";c.ajax({url:"//api.microsofttranslator.com/V2/Ajax.svc/TranslateArray?appId="+t_jp.msn_key+"&to="+d+"&texts="+f,dataType:"jsonp",jsonp:"oncomplete",success:a})}else 1===z?setTimeout(function(){p(b,a,d)},500):(z=1,c.getScript("//www.microsofttranslator.com/ajax/v2/toolkit.ashx?loc=en&toolbar=none",function(){t_jp.msn_key=_mstConfig.appId;p(b,a,d)}))}function G(b,
a){s=2;p(a,function(a){c(a).each(function(a){l(b[a],this.TranslatedText)})},t_jp.binglang)}function A(b,a,d){c.ajax({url:"http://api.apertium.org/json/translate",data:{q:b,langpair:t_jp.olang+"|"+d,markUnknown:"no"},dataType:"jsonp",traditional:!0,success:a})}function H(b,a){s=3;A(a,function(a){200<=a.responseStatus&&300>a.responseStatus&&(void 0!==a.responseData.translatedText?l(b[0],a.responseData.translatedText):c(a.responseData).each(function(a){200===this.responseStatus&&l(b[a],this.responseData.translatedText)}))},
t_jp.lang)}function B(b,a){!t_jp.msn||"2"!==t_jp.preferred&&void 0!==t_jp.google?!t_jp.apertium||"en"!==t_jp.olang&&"es"!==t_jp.olang?t_jp.google_key?F(b,a):x(b,a):H(b,a):G(b,a)}function u(){var b=[],a=0,d=[],f=[];c("."+e+'[data-source=""]').each(function(){var e=c(this).attr("data-token"),g=c(this).attr("data-orig");void 0===g&&(g=c(this).html());1!==b[g]&&(b[g]=1,a+encodeURIComponent(g).length>I&&(B(f,d),a=0,d=[],f=[]),a+=encodeURIComponent(g).length,f.push(e),d.push(g))});B(f,d)}function C(b){"function"===
typeof c.xLazyLoader?b():(t_jp.$=c,c.getScript(t_jp.plugin_url+"/js/lazy.js",b))}function q(b){q.hit?b():(q.hit=!0,C(function(){c.fn.propAttr=c.fn.prop||c.fn.attr;c.xLazyLoader({js:t_jp.jQueryUI+"jquery-ui.min.js",css:t_jp.jQueryUI+"themes/"+t_jp.theme+"/jquery-ui.css",success:b})}))}var I=1024,k,e=t_jp.prefix,n=e+"pbar",m=n+"_s",s=1,t=0,v,h=[],r=[],z=0;t_jp.dgpt=w;t_jp.dgt=y;t_jp.dmt=p;t_jp.dat=A;t_jp.tfl=C;t_jp.tfju=q;t_jp.at=u;c(function(){t_jp.msn&&(t_jp.binglang=t_jp.lang,"zh"===t_jp.binglang?
t_jp.binglang="zh-chs":"zh-tw"===t_jp.binglang?t_jp.binglang="zh-cht":"mw"===t_jp.binglang&&(t_jp.binglang="mww"));c("."+e+"setdeflang").click(function(){c.ajax({url:t_jp.ajaxurl,data:{action:"tp_cookie"},cache:!1});c("."+e+"setdeflang").hide("slow");return!1});k=c("."+e+'[data-source=""]').size();c.ajaxSetup({cache:!0});k&&!t_jp.noauto&&(t_jp.google||t_jp.msn||t_jp.apertium)&&(t_jp.progress?q(function(){c("#"+e+"credit").css({overflow:"auto"}).append('<div style="float: left;width: 90%;height: 10px" id="'+
n+'"/><div style="margin-bottom:10px;float:left;width: 90%;height: 10px" id="'+m+'"/>');c("#"+n).progressbar({value:0});c("#"+m).progressbar({value:0});c("#"+m+" > div").css({background:"#28F828",border:"#08A908 1px solid"});u()}):u());t_jp.edit&&c.getScript(t_jp.plugin_url+"/js/transposhedit.js")})})(jQuery);
What should I add in the checkout.js to fire the translations everytime the cart is updated?
Let me know what other details I should provide.
EDIT: I should note that I was told that the cart is being updated via AJAX. Upon research, the plugin creator of transposh had suggested users to look at the on_init function in transposh.php
This is the on_init function:
/**
* Setup a buffer that will contain the contents of the html page.
* Once processing is completed the buffer will go into the translation process.
*/
function on_init() {
tp_logger('init ' . $_SERVER['REQUEST_URI'], 4);
// the wp_rewrite is not available earlier so we can only set the enable_permalinks here
if (is_object($GLOBALS['wp_rewrite'])) {
if ($GLOBALS['wp_rewrite']->using_permalinks() && $this->options->enable_permalinks) {
tp_logger("enabling permalinks");
$this->enable_permalinks_rewrite = TRUE;
}
}
// this is an ajax special case, currently crafted and tested on buddy press, lets hope this won't make hell break loose.
// it basically sets language based on referred when accessing wp-load.php (which is the way bp does ajax)
tp_logger(substr($_SERVER['SCRIPT_FILENAME'], -11), 5);
if (substr($_SERVER['SCRIPT_FILENAME'], -11) == 'wp-load.php') {
$this->target_language = transposh_utils::get_language_from_url($_SERVER['HTTP_REFERER'], $this->home_url);
$this->attempt_json = true;
}
//buddypress old activity
if (#$_POST['action'] == 'activity_get_older_updates') {
$this->target_language = transposh_utils::get_language_from_url($_SERVER['HTTP_REFERER'], $this->home_url);
$this->attempt_json = true;
}
tp_logger($_SERVER['REQUEST_URI'], 5);
if (strpos($_SERVER['REQUEST_URI'], '/wpv-ajax-pagination/') === true) {
tp_logger('wpv pagination', 5);
$this->target_language = transposh_utils::get_language_from_url($_SERVER['HTTP_REFERER'], $this->home_url);
}
// load translation files for transposh
load_plugin_textdomain(TRANSPOSH_TEXT_DOMAIN, false, dirname(plugin_basename(__FILE__)) . '/langs');
//set the callback for translating the page when it's done
ob_start(array(&$this, "process_page"));
}
Here is the function for update_checkout()
function update_checkout() {
if (xhr) xhr.abort();
if ( $('select#shipping_method').size() > 0 || $('input#shipping_method').size() > 0 )
var method = $('#shipping_method').val();
else
var method = $('input[name=shipping_method]:checked').val();
var payment_method = $('#order_review input[name=payment_method]:checked').val();
var country = $('#billing_country').val();
var state = $('#billing_state').val();
var postcode = $('input#billing_postcode').val();
var city = $('input#billing_city').val();
var address = $('input#billing_address_1').val();
var address_2 = $('input#billing_address_2').val();
if ( $('#shiptobilling input').is(':checked') || $('#shiptobilling input').size() == 0 ) {
var s_country = country;
var s_state = state;
var s_postcode = postcode;
var s_city = city;
var s_address = address;
var s_address_2 = address_2;
} else {
var s_country = $('#shipping_country').val();
var s_state = $('#shipping_state').val();
var s_postcode = $('input#shipping_postcode').val();
var s_city = $('input#shipping_city').val();
var s_address = $('input#shipping_address_1').val();
var s_address_2 = $('input#shipping_address_2').val();
}
$('#order_methods, #order_review').block({message: null, overlayCSS: {background: '#fff url(' + woocommerce_params.ajax_loader_url + ') no-repeat center', backgroundSize: '16px 16px', opacity: 0.6}});
var data = {
action: 'woocommerce_update_order_review',
security: woocommerce_params.update_order_review_nonce,
shipping_method: method,
payment_method: payment_method,
country: country,
state: state,
postcode: postcode,
city: city,
address: address,
address_2: address_2,
s_country: s_country,
s_state: s_state,
s_postcode: s_postcode,
s_city: s_city,
s_address: s_address,
s_address_2: s_address_2,
post_data: $('form.checkout').serialize()
};
xhr = $.ajax({
type: 'POST',
url: woocommerce_params.ajax_url,
data: data,
success: function( response ) {
if ( response ) {
var order_output = $(response);
$('#order_review').html(order_output.html());
$('body').trigger('updated_checkout');
}
}
});
}
After a bit of digging , and because im not php expert neither wp expert , but i can tell where the issue is.
First of all you should understand what add_action is , it is well explained here
If you needed to create an AJAX handler for an "add_foobar" request, you would create a hook like this:
add_action( 'wp_ajax_add_foobar', 'prefix_ajax_add_foobar' );
add_action( 'wp_ajax_nopriv_add_foobar', 'prefix_ajax_add_foobar' );
function prefix_ajax_add_foobar() {
// Handle request then generate response using WP_Ajax_Response
}
Using the above example, any time an AJAX request is sent to WordPress, and the request's 'action' property is set to 'add_foobar', this hook will be automatically executed. For example, the following code would execute the above hook.
jQuery.post(
ajaxurl,
{
'action': 'add_foobar',
'data': 'foobarid'
},
function(response){
alert('The server responded: ' + response);
}
);
so now you got how actions works , then you have to get how the transposh.php ajax part works , from the transposh.php file ( i recommend you open the file in a good text editor like sublime text ) , in line 437 :
//buddypress old activity
if (#$_POST['action'] == 'activity_get_older_updates') {
$this->target_language = transposh_utils::get_language_from_url($_SERVER['HTTP_REFERER'], $this->home_url);
$this->attempt_json = true;
}
this simply tells our script to fire translation when this action is called, what you have to do is customizing this line a bit so it fires upon you ajax request (update_checkout()).
if you check update_checkout() function you will find the corresponding action : 'woocommerce_update_order_review'
Solution:
1. Add you wp actions
add_action( 'wp_woocommerce_update_order_review', 'woocommerce_update_order_review' );
//preferably add this to line 207 in transposh.php with other add actions.
2. Instead of adding your own function , just modify the current buddypress example.
if (#$_POST['action'] == 'activity_get_older_updates')
to be
if (#$_POST['action'] == 'activity_get_older_updates' || #$_POST['action'] == 'woocommerce_update_order_review' )
//fire translation if action is equal to buddypress activity get older updates or action is equal to woocommerce update checkout.
3. this guy recommends adding following condition to line 352 in transposh.php
if ($this->is_special_page($_SERVER['REQUEST_URI']))
to be
if ($this->is_special_page($_SERVER['REQUEST_URI'])&& !$this->attempt_json)
found here : http://cl.ly/Shdn/o
I hope i had a link to your page where you are using this , but you could not provide an example , so i hope this solution will work as it was meant to be.
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.