I've a form that use Jquery Form to make a ajax request upload file to server. It's all good and I've made a function that before user click "upload" button, they can view all the files in the input type = "file" in a table, each row has a delete button to delete this row if you don't want to upload the file in this row.
But I don't know how to really delete the file in javascript this.files array? I've known that this is security error then Javascript cannot change the value of input file.
So, how can I simulate a array of files which user has chosen and delete to post request to server?
Please help me!
NOTE: I've solved the problem by myself, and I want to share for someone who want to have a delete file from input multiples. Please, refer to this link
AJAX/PHP based upload with progress bar for large files
In here, you'll have to use xmlHTTPRequest to post file from the list you want to server. So if user deleted some file name in row, your file array will update too. After all, you update your array to server, each element, each xhr request.
Thanks for anybody.
xhr.setRequestHeader("Cache-Control", "no-cache");
xhr.setRequestHeader("Content-Type", "multipart/form-data");
xhr.setRequestHeader("X-File-Name", fileToUpload.name);
xhr.setRequestHeader("X-File-Size", fileToUpload.size);
xhr.setRequestHeader("X-File-Type", fileToUpload.type);
//xhr.setRequestHeader("Content-Type", "application/octet-stream");
Here is my html
<form action="processupload.php" method="post" enctype="multipart/form-data" id="MyUploadForm">
<!-- file input not disable it, just hide by position !-->
<input name="FileInput[]" id="FileInput" type="file" multiple style="position: absolute;left: -9999px;"/>
Add Files
<input type="submit" id="submit-btn" value="Upload" style="display:inline;"/>
<img src="images/ajax-loader.gif" id="loading-img" style="display:none;" alt="Please Wait"/>
</form>
Here is my Javascript
// when change fileinput then get it files name and put to array to check new file or not
$('#FileInput').change(function(e){
if(arrayFiles.length == 0)
{
for (var i = 0; i < this.files.length; i++)
{
// alert(this.files[i].name);
fileNameNew = this.files[i].name;
// Check file is valid
if(checkFileValid(this.files[i]))
{
arrayFiles.push(fileNameNew);
}
}
}
// check if new file is in arrayFiles or not
else
{
// check if file name is same in arrayFiles
for(var i = 0; i < this.files.length; i++)
{
fileNameNew = this.files[i].name;
flag = true;
for(var j=0; j < arrayFiles.length; j++)
{
fileNameOld = arrayFiles[j];
if(fileNameOld == fileNameNew)
{
flag = false;
break; // same file name then not need to push to arrayFiles
}
}
// file is new in arrayFiles
if(flag == true)
{
// fileNameNew is not in arrayFiles so push it to arrayFiles
if(checkFileValid(this.files[i])) // check file name is .hdf
{
arrayFiles.push(fileNameNew);
}
}
}
} // end else check upload new files name
// alert(arrayFiles.length);
// rerender the tbody of table id = "files"
/*
$('#files').find('tbody').append("<tr id='row1'><td>1</td><td>ABC123</td><td><a href='#' name='deleteRow' id='delRow_1'>Delete</a></td></tr><tr id='row2'><td>2</td><td>ABCE1234</td><td><a href='#' name='deleteRow' id='delRow_2'>Delete</a></td></tr><tr id='row3'><td>3</td><td>3242efsdfEWRweR3</td><td><a href='#' name='deleteRow' id='delRow_3'>Delete</a></td></tr>");
*/
tableFilesRender(arrayFiles);
alert($("#FileInput").val(''));
});
// render tbody of table id = "files"
function tableFilesRender(arrayFiles)
{
// clear the table files tbody first
$("#files > tbody").html("");
// iterrate the arrayFiles and write the array row
content = "";
// Row like this: <tr id='row1'><td>1</td><td>ABC123</td><td><a href='#' name='deleteRow' id='delRow_1'>Delete</a></td></tr>
for(var i = 0; i < arrayFiles.length; i++)
{
trStart = "<tr id='row" + i + "'>";
td1 = "<td>" + (i + 1) + "</td>";
td2 = "<td>" + arrayFiles[i] + "</td>";
td3 = "<td><a href='#' name ='deleteRow' id = 'delRow_" + i + "'>Delete</a></td>";
trEnd = "</tr>";
content += trStart + td1 + td2 + td3 + trEnd;
}
// append content to table #files
$('#files').find('tbody').append(content);
}
// Check file is valid type
function checkFileValid(file)
{
fileExtension = file.name.split('.').pop();
if(fileExtension == "hdf")
{
return true;
}
alert(file.name + " không hợp lệ, phải là dạng file HDF .hdf!");
return false;
}
// handle event delete row (created dynamicall), need to get the closet father is #files table and the selector [name='deleteRow']
$("#files").on("click", "[name='deleteRow']", function(event){
deleteID = $(this).attr("id");
temp = deleteID.split("_");
rowID = "row" + temp[1];
// remove the arrayFiles at rowID
arrayFiles.splice(temp[1], 1);
//alert(rowID);
$("#files #" + rowID).remove(); // remove rowID on files table only
//alert(temp[1] + "Link is clicked!");
// delete success then rerender the tables files
tableFilesRender(arrayFiles);
});
Related
Here is the code I'm using now:
function emailQuestionnaireAsPDF(questionnaireKey) {
if (app.getActiveUserRoles().indexOf(app.roles.Admins) === -1) {
throw new Error('You don\'t have permissions to perform this operation');
}
var questionnaire = app.models.Questionnaire.getRecord(questionnaireKey);
if (!questionnaire) {
throw new Error('Questionnaire was not found');
}
var tmpDoc = DocumentApp.create(FILE_NAME + ' ' + Date.now());
var body = tmpDoc.getBody();
var title = questionnaire.FirstName + '\'s Questionnaire';
var fields = app.metadata.models.Questionnaire.fields;
body.insertParagraph(0, title)
.setHeading(DocumentApp.ParagraphHeading.HEADING1)
.setAlignment(DocumentApp.HorizontalAlignment.CENTER);
appendField_(body, fields.FirstName.displayName,
questionnaire.FirstName);
appendField_(body, fields.LastName.displayName,
questionnaire.LastName);
appendField_(body, fields.LikeIceCream.displayName,
questionnaire.LikeIceCream);
appendField_(body, fields.FavoriteMovie.displayName,
questionnaire.FavoriteMovie);
appendField_(body, fields.FavoriteColor.displayName,
questionnaire.FavoriteColor);
appendField_(body, fields.LuckyNumber.displayName,
questionnaire.LuckyNumber);
tmpDoc.saveAndClose();
var blob = tmpDoc.getAs(MimeType.PDF);
var pdfFile = DriveApp.createFile(blob);
Drive.Files.remove(tmpDoc.getId());
pdfFile.setName(FILE_NAME);
sendEmail_(Session.getActiveUser().getEmail(), FILE_NAME, pdfFile.getUrl());
}
I'm trying to append all fields, from a model related to Questionnaire, to the "pdfFile". How is this done in a way all fields & values associated are pasted to the pdfFile in a table like format?
Based on your description, this is what I've done:
Created a model called questionnaire with the following fields:
firstName
lastName
likeIcecream
favoriteMovie
favoriteColor
luckyNumber
I added a couple of test records. Then on the server script I added two functions. The first one to send email looks like this:
function sendEmail(recipient, fileUrl, fileName){
var pdfBlob = UrlFetchApp.fetch(fileUrl).getAs("application/pdf");
MailApp.sendEmail({
to: recipient,
subject: "PDF Email Sample",
htmlBody: "Attached the PDF File",
attachments: [pdfBlob]
});
}
The second function to generate the document looks like this:
function emailQuestionnaireAsPDF(questionnaireKey){
if (app.getActiveUserRoles().indexOf(app.roles.Admins) === -1) {
throw new Error('You don\'t have permissions to perform this operation');
}
var questionnaire = app.models.questionnaire.getRecord(questionnaireKey);
if (!questionnaire) {
throw new Error('Questionnaire was not found');
}
//Start generating the HTML template
var htmlData = "";
htmlData += "<h1 style='text-align:center'>" + questionnaire.firstName + "'s Questionnaire </h1><br>"; //Title of the document
//Create table start tag
htmlData += "<table style='border:none;'>";
//Create headers and append to table
var headers = ["QUESTION", "RESPONSE"];
var hRowStyle = "background-color:#efefef"; //style for table header row
var hCellStyle = "font-weight:bold; padding-top:4px; padding-bottom: 3px; border-bottom:1px solid #bebebe;"; //style for table header cells
htmlData += "<tr style='"+hRowStyle+"'><td style='"+hCellStyle+"'>" + headers.join("</td><td style='"+hCellStyle+"'>") + "</td></tr>";
//Define row cell styles
var tdSytle = "border-bottom: 1px solid #bebebe; border-left:0px; border-right:0px; padding-top:7px; padding-bottom: 6px;";
//Create table rows
var rows = [];
rows.push(["First Name:", questionnaire.firstName]); // Add firstName
rows.push(["Last Name:", questionnaire.lastName]); // Add lastName
rows.push(["Likes Icecream:", questionnaire.likeIcecream]); // Add likeIceacream
rows.push(["Favorite Movie:", questionnaire.favoriteMovie]); // Add favoriteMovie
rows.push(["Favorite Color:", questionnaire.favoriteColor]); // Add favoriteColor
rows.push(["Lucky Number:", questionnaire.luckyNumber]); // Add luckyNumber
//Append rows to table
rows.forEach(function(row){
htmlData += "<tr><td style='"+tdSytle+"'>" + row.join("</td><td style='"+tdSytle+"'>") + "</td><tr>";
});
//Create table end tag
htmlData += "</table>";
//Create gooleDriveDoc
var fileName = questionnaire.firstName + "'s Questionnaire";
var data = Utilities.newBlob("").setDataFromString(htmlData).setContentType("text/html");
var drvFile = Drive.Files.insert({title: fileName}, data, {convert: true});
//Mail PDF File
var recipient = "email#test.com";
var fileUrl = "https://docs.google.com/document/d/"+drvFile.id+"/export?format=pdf&access_token="+ScriptApp.getOAuthToken();
sendEmail(recipient, fileUrl, fileName);
}
So, in summary, I've created a google document from an HTML template. Then, I used the download url with an access token to fetch the pdf Blob and attach it to the email.
The result is the following:
Reading through the code you should be able to catch what it's being done in detail and of course, you can improve it!
References:
https://developers.google.com/drive/api/v2/reference/files/insert
https://developers.google.com/apps-script/reference/mail/mail-app#sendEmail(String,String,String,Object)
https://developers.google.com/apps-script/reference/base/blob
https://developers.google.com/identity/protocols/OAuth2WebServer#callinganapi
https://developers.google.com/apps-script/reference/script/script-app#getoauthtoken
https://developers.google.com/drive/api/v2/reference/files/get
https://www.labnol.org/internet/direct-links-for-google-drive/28356/
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
}
Following is my code which upload files on server using dropzone.js plugin:
var file_up_names = new Array;
var duplicate_files = new Array;
var token = $('input[name=_token]').val();
Dropzone.autoDiscover = false;
var dropzone = $("#addPhotosForm").dropzone({
addRemoveLinks: true,
dictRemoveFileConfirmation: "Do you want to remove this image?",
dictDefaultMessage: "Drop images here to upload",
dictRemoveFile: "Remove photo",
init: function() {
this.on("success", function(file, response) {
if (response.status === 1) {
file_up_names.push(response.filename);
$(file.previewTemplate).append('<span class="server_file_path hide">' + response.newfilename + '</span>');
} else if (response.status === 2) {
duplicate_files.push(response.filename);
this.removeFile(file);
}
}),
this.on("queuecomplete", function() {
var html = "Photos added successfully!";
$('#photoUploadSuccess').html('');
$('#photoUploadError').html('');
$('#photoUploadSuccess').removeClass('hide');
$('#photoUploadError').addClass('hide');
if (file_up_names.length > 0) {
if (duplicate_files.length > 0) {
html += " Following photos are skipped as those are already uploaded.";
html += "<ul>";
for (var i = 0; i < duplicate_files.length; ++i) {
html += "<li>";
html += duplicate_files[i];
html += "</li>";
}
html += "</ul>";
}
$('#photoUploadSuccess').html(html);
} else if (duplicate_files.length > 0 && file_up_names.length === 0) {
html = "Following photos already exists. Please check to see if it already exists and try again.";
html += "<ul>";
for (var i = 0; i < duplicate_files.length; ++i) {
html += "<li>";
html += duplicate_files[i];
html += "</li>";
}
html += "</ul>";
$('#photoUploadSuccess').addClass('hide');
$('#photoUploadError').removeClass('hide');
$('#photoUploadError').html(html);
} else {
html = "Photos not uploaded!";
$('#photoUploadSuccess').addClass('hide');
$('#photoUploadError').removeClass('hide');
$('#photoUploadError').html(html);
}
duplicate_files = [];
file_up_names = [];
setTimeout(function() {
$('#photoUploadSuccess').html('');
$('#photoUploadError').html('');
$('#photoUploadSuccess').addClass('hide');
$('#photoUploadError').addClass('hide');
}, 5000);
}),
this.on("removedfile", function(file) {
var server_file = $(file.previewTemplate).children('.server_file_path').text();
// Do a post request and pass this path and use server-side language to delete the file
var token = $('input[name=_token]').val();
$.ajax({
type: 'POST',
headers: {'X-CSRF-TOKEN': token},
url: "{{ URL::route('removePhotos') }}",
data: "file_name=" + server_file,
dataType: 'html'
});
})
}
});
While below is my server code which get file's md5 and store it on server and next time when user upload same image again it check in database and if same md5_file result found it won't allow to upload image. It work when i use simple form, but on dropzone it's not working:
$tempFile = $_FILES['file']['tmp_name'];
$md5_check = md5_file($tempFile);
//check if same image uploaded before
$duplicateCheck = Photos::where('userId', '=', $this->userId)->where('md5_check', '=', "$md5_check")->where('isDeleted', '=', 0)->count();
I've found that if I upload same images together it won't work and return count 0 from DB. But if I upload same images separately like for example upload image once it uploads, upload same image again it get count from DB and give message that image already there. Maybe it's due to dropzone asynchronous calls but can't figure it out how to handle this.
It's because when you upload more than one image $_FILES contains an array of files, so you should cycle it with a foreach and do your operations inside that loop.
You can check what's happening when you upload more than 1 files by inserting this line of code:
var_dump($_FILES);
Or if you want a result better readable:
echo "<pre>".print_r($_FILES, true)."</pre>";
Check the structure of $_FILES when you upload more than 1 file, it should be an array of files.
Hi I have gone through various link to update a cell value like here also here
I need to change the image which I put through a custom formatter as soon as user clicks on the image. So, I was using onCellSelect event where I am getting the data of the row by this
var data = $(this).jqGrid('getRowData', row);
And then I am changing the value of the cell by this -
image = "results_not_available.png";
data.colyesno = "<img title ='Detail data not available' src='img/" + image + "' />";
and the updating the cell value by setRowData
$(this).jqGrid('setRowData', row, data);
All the other links show this is a workable solution. I even tried to change any string column that too it is not working for me.
What else can I do?
Update: For me, setRowData is setting the title for the cell, not the value.
1) How I am adding an image -
I am using a custom formatter for that-
function resultsImage(cellValue, options, rowdata, action) {
var image = "";
if (cellValue == "Y"){
image = "results_available.png";
var imageHtml = "<img class=pointer title ='Detail data available. Click to request for data' src='img/" + image + "' />";
return imageHtml;
}
else if (cellValue == "N"){
image = "results_not_available.png";
var imageHtml = "<img title ='Detail data not available' src='img/" + image + "' />";
return imageHtml;
}
}
So, here inside the cell, I am placing an image.
On cell select, I am taking the data and calling a function -
onCellSelect: function(row, col, content, event) {
var cm = jQuery(grid).jqGrid("getGridParam", "colModel");
columnName = cm[col].name;
var data = $(this).jqGrid('getRowData', row);
if(columnName == 'col_image')
callImage(data,content);
$(this).jqGrid('setRowData', row, data);
}
Now here I am checking some condition so to which image needs to be applied.
var callImage = function (data,content){
if(condition==true) { ///which is some variable where we make some request to server and it returns backs a variable
image = "loading_completed.png";
data.col_image = "<img title ='Click to view data' src='img/" + image + "' />";
return data
};
else {
image = "loading_error.png";
data.col_image = "<img title ='No data available' src='img/" + image + "' />";
return data
};
}
So, if the user clicks on an image not in the cell then the image src should change according to the condition and it change should reflect in the same place as the old image.
You can use event parameter of onCellSelect callback. event.target will be element, clicked by user. Below is the example of the code:
onCellSelect: function (iRow, iCol, content, event) {
var cmName = $(this).jqGrid("getGridParam", "colModel")[iCol].name,
target = event.target;
if (cmName === "col_image" && target.tagName.toUpperCase() === "IMG") {
if (condition) { // some kind of testing
target.src = "img/loading_completed.png";
target.title = "Click to view data";
// one can use $(target).attr alternatively
//$(target).attr({
// src: "img/loading_completed.png",
// title: "Click to view data"
//});
} else {
target.src = "img/loading_error.png";
target.title = "No data available";
// one can use $(target).attr alternatively
//$(target).attr({
// src: "img/loading_error.png",
// title: "No data available"
//});
}
}
}
I am trying to make an image take a value in as a source, after the image tag (and a related radio button) has been created using JavaScript. I have discerned the following from testing and alert outputs:
If the image src is provided at the creation of the image tag using an exact filepath, it will show the image correctly (e.g. src='images/0.jpg'). However, this is not helpful since I need it to work for any given image, not a specific one.
If the image src is provided at the creation of the image tag using a variable containing a filepath, it fails to generate the image tag or the radio button at all (e.g. src='" + result + '").
NOTE: The last example is not present in the code below. The result was found by moving the '$.post' section to the line directly under the 'out +=' line within the for loop.
If the image src is left blank at the creation of the image tag, the image tag and radio button are created, though the image is blank as expected. If I then try to use 'getElementByID(imgID).src' to change the image source after this, it fails to do anything. ('imgID' here is an example, not what the code says).
On top of the above, using alerts and dumping info into divs indicate that the comicID is being correctly posted, and the filepath of the image src is definitely being found, and is being copied into the variable 'result' correctly, even one line before the creation of the tag or the attempt to edit it using 'getElementById'.
At this point I'm stumped, I don't know what could logically be stopping the src from reading in.
--
Javascript:
<script>
// Loads the user's comic list from the database.
function loadComic()
{
var xmlhttp = new XMLHttpRequest();
var getID = '<?php echo $_SESSION["userID"]; ?>';
var url = "loadCom.php?userID="+getID;
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState == 4 && xmlhttp.status == 200)
{
loadComicJSON(xmlhttp.responseText);
}
}
xmlhttp.open("GET", url, true);
xmlhttp.send();
}
// JSON parsing for 'loadComic'.
function loadComicJSON(response)
{
var arr = JSON.parse(response);
var i;
var out = "";
document.getElementById("loadList").innerHTML="";
if (arr.length == 0)
{
//Irrelevant manipulation of HTML.
}
else
{
out+="<br>";
for(i = 0; i < arr.length; i++)
{
out += "<hr><br><img name = '" + ('cm' + arr[i].comicID) + "' id='" + ('com' + arr[i].comicID) + "' onclick='resizeThumb(this)' height='100px;' src='' ><input name='comicList' type='radio' id='" + arr[i].comicID + "' value='" + arr[i].comicID + "'>" + arr[i].comicName + " </option><br><br>";
}
document.getElementById("loadList").innerHTML=out;
for(j=0; j< arr.length; j++)
{
tempID = (arr[j].comicID);
$.post("getCover.php", {comicID:tempID}, function(result)
{
document.getElementById("loadList").innerHTML+="<p>"+result+"</p>";
document.getElementById("com"+arr[j].comicID).src = result;
}
);
}
}
}
</script>
PHP (getCover.php):
<?php
if (isset($_POST["comicID"]))
{
include_once('includes/conn.inc.php');
$checkID = $_POST["comicID"];
$query = ("SELECT pageLocation FROM page WHERE comicID = '$checkID' ORDER BY pageNum");
$result = mysqli_query($conn, $query);
$row = mysqli_fetch_assoc($result);
print_r($row["pageLocation"]);
}
else
{
$checkID = null;
echo "Error. No comic found.";
}
?>
To my knowledge, loadList.php is working perfectly, so I didn't list its code to keep things relevant.
I copied your code and tweaked it a little so I could run it without the web services and it works great. Here is the HTML page I created:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<script>
// JSON parsing for 'loadComic'.
function loadComicJSON()
{
var arr = [{comicID: 1},{comicID: 2},{comicID: 3}];
var result = "monkey.jpeg";
var i;
var out = "";
document.getElementById("loadList").innerHTML="";
if (arr.length == 0)
{
//Irrelevant manipulation of HTML.
}
else
{
out+="<br>";
for(i = 0; i < arr.length; i++)
{
out += "<hr><br><img name = '" + ('cm' + arr[i].comicID) + "' id='" + ('com' + arr[i].comicID) + "' onclick='resizeThumb(this)' height='100px;' src='' ><input name='comicList' type='radio' id='" + arr[i].comicID + "' value='" + arr[i].comicID + "'>" + arr[i].comicName + " </option><br><br>";
}
document.getElementById("loadList").innerHTML=out;
for(j=0; j< arr.length; j++)
{
var imgSrc;
tempID = (arr[j].comicID);
document.getElementById("loadList").innerHTML+="<p>"+result+"</p>";
document.getElementById("com"+arr[j].comicID).src = result;
}
}
}
</script>
</head>
<body>
<div id="loadList"></div>
<button onclick="loadComicJSON()">Try it</button>
</body>
</html>
As you can see, I created an array of JSON objects that hold the comicID and am statically creating the image as 'monkey.jpeg'.
The code works so there is either an issue with the 'response' that you pass into your loadComicJSON method or the result from your POST method.
Add a couple of console.log statements and look at the two values I mentioned and you will likely see the issue.
Solved the issue myself. It turned out that the $.post needed to be $.get and that it needed to technically be outside of a loop (i.e. in its own function) to work properly. Works fine now after that and a couple minor tweaks.