Related
I have array with the multiple records, each record has ID, event name and customer name. My algorithm that I use does not seem to work the way I want. Before I start to loop through array I set the empty variable outside of the loop var eventId; then I started looping and inside of the loop I have multiple if statement. So if eventId is empty I want to append tr with event name and below that another tr with customer name. Then next time if my eventId is not empty I want to check if name match with the record, if they match I just want to append td inside of existing tr and output customer name. If they do not match I want to output new tr with event name and new tr with customer name. I have working example here, it looks like that I have Test 1 outputted twice on the screen and I do not want that. I should have event name only once and all customers for that event below that event.
Here is my code:
https://jsfiddle.net/dmilos89/t1v2r8jm/3/
Please if you see where my code is breaking let me know. I think that I have problem with appending elements or my algorithm is missing something. Thanks in advance.
Javascript code:
$( document ).ready(function() {
var myRes = [];
myRes.push({'myId':"42",'eventName':"Test 1",'rCustomer':"Mike, Allan"});
myRes.push({'myId':"42",'eventName':"Test 1",'rCustumer':"Gates, Bill"});
myRes.push({'myId':"19",'eventName':"Spring 2016",'rCustomer':"John, Bill"});
myRes.push({'myId':"19",'eventName':"Spring 2016",'rCustomer':"Adams, Ron"});
myRes.push({'myId':"31",'eventName':"May Test 1",'rCustomer':"Steve, Marie"});
myRes.push({'myId':"42",'eventName':"Test 1",'rCustomer':"Ariel, Bill"});
myRes.push({'myId':"32",'eventName':"Fall 2016",'rCustomer':"Ron, Nill"});
myRes.push({'myId':"32",'eventName':"Fall 2016",'rCustomer':"Kim, Alen"});
myRes.push({'myId':"32",'eventName':"Fall 2016",'rCustomer':"Will, Huges"});
myRes.push({'myId':"32",'eventName':"Fall 2016",'rCustomer':"Seth, Peak"});
var eventId = '';
var count = 1;
for(var i=0; i< myRes.length; i++){
if(eventId != ''){
if(eventId == myRes[i].myId){
$('#row_' + count).append('<td>'+myRes[i].rCustomer+'</td>');
}else{
eventId = myRes[i].myId;
count++;
$('.myReservation').append('<tr><td><b>Event: '+myRes[i].eventName+'</b></td></tr>');
$('.myReservation').append('<tr id="row_"'+count+'><td>'+myRes[i].rCustomer+'</td></tr>');
}
}else{
eventId = myRes[i].myId;
$('.myReservation').append('<tr><td><b>Event: '+myRes[i].eventName+'</b></td></tr>');
$('.myReservation').append('<tr id="row_"'+count+'><td>'+myRes[i].rCustomer+'</td></tr>');
}
}
});
HTML code:
<table>
<tbody class="myReservation">
</tbody>
</table>
You misplaced the double quote when inserting tr elements with ids.
Replace <tr id="row_"'+count+'> with <tr id="row_'+count+'">.
Update: this achieves what you (probably) want:
var found = [];
for (var i = 0; i < myRes.length; i++) {
if (found[myRes[i].myId] === 1) {
$('#row_' + myRes[i].myId).append('<td>' + myRes[i].rCustomer + '</td>');
} else {
found[myRes[i].myId] = 1;
$('.myReservation').append('<tr><td><b>Event: ' + myRes[i].eventName + '</b></td></tr>');
$('.myReservation').append('<tr id="row_' + myRes[i].myId + '"><td>' + myRes[i].rCustomer + '</td></tr>');
}
}
Your problem is that you append a new element on every loop:
First, you are testing if "eventId" is not empty. If it is, you are setting it with the current loop iteration "myId"
eventId = myRes[i].myId;
$('.myReservation').append('<tr><td><b>Event: '+myRes[i].eventName+'</b></td></tr>');
$('.myReservation').append('<tr id="row_"'+count+'><td>'+myRes[i].rCustomer+'</td></tr>');
According to your data, eventId is now 42 and your output is :
<tr><td><b>Event: Test 1</b></td></tr>
<tr id="row_" 1=""><td>Mike, Allan</td></tr>
(by the way, there is a syntax error here and it explains why the next iteration doesn't append data)
Then, on the next iteration, eventId is still 42 so you are doing this
$('#row_' + count).append('<td>'+myRes[i].rCustomer+'</td>');
The output is the same at this point (see above the syntax error on the first answer)
On the next loop iteration, myId will be now 19 so you are overriding eventid and appending tr in consequence
loops keep going...
Until myId is again equal to 42 :
myRes.push({'myId':"42",'eventName':"Test 1",'rCustomer':"Ariel, Bill"});
Here you doesn't want "Event: Test 1" appearing two times, but on the last loop iteration myId was 31
myRes.push({'myId':"31",'eventName':"May Test 1",'rCustomer':"Steve, Marie"});
So on the if test, eventId is NOT equal to myRes[i].myId, therefore your script appends a new tr with duplicate event.
One solution could be this one:
$( document ).ready(function() {
var myRes = [];
myRes.push({'myId':"42",'eventName':"Test 1",'rCustomer':"Mike, Allan"});
myRes.push({'myId':"42",'eventName':"Test 1",'rCustomer':"Gates, Bill"});
myRes.push({'myId':"19",'eventName':"Spring 2016",'rCustomer':"John, Bill"});
myRes.push({'myId':"19",'eventName':"Spring 2016",'rCustomer':"Adams, Ron"});
myRes.push({'myId':"31",'eventName':"May Test 1",'rCustomer':"Steve, Marie"});
myRes.push({'myId':"42",'eventName':"Test 1",'rCustomer':"Ariel, Bill"});
myRes.push({'myId':"32",'eventName':"Fall 2016",'rCustomer':"Ron, Nill"});
myRes.push({'myId':"32",'eventName':"Fall 2016",'rCustomer':"Kim, Alen"});
myRes.push({'myId':"32",'eventName':"Fall 2016",'rCustomer':"Will, Huges"});
myRes.push({'myId':"32",'eventName':"Fall 2016",'rCustomer':"Seth, Peak"});
myRes.forEach(function(value, key) {
var table = $('.myReservation2');
var elemInTable = table.find('tr#row_'+value.myId); // $('#row_42') as an example
// If row doesn't exists, create it with it's customers
if(!elemInTable.length) {
table.append('<tr id="row_'+value.myId+'"><td>'+value.eventName+'</td></tr>');
elemInTable = table.find('tr#row_'+value.myId);
elemInTable.after('<tr><td>'+value.rCustomer+'</td></tr>');
}
// If it already exists, simply add the customers
else {
elemInTable.after('<tr><td>'+value.rCustomer+'</td></tr>');
}
})
});
However, I don't think it is the proper way to do it, actually, I think that you should reorganize your data (if your context permits it) like this :
myRes.push({'myId':"42",'eventName':"Test 1",'rCustomer': ["Mike, Allan", "Gates", "Bill", "..."]})
(sorry for my english by the way)
I have a tablesorter table that is generated dynamically with javascript and ajax. There are inputs for the user to change values, and when they click a button to go to the next or previous record, it needs to save the information in the table to a MySQL table. I have looked at many of the posts on here and tried numerous examples, and I still can't get any of the data in the table to post to my PHP page to save it.
Here is a sample of the first row of my table:
$("#guides").append('<tr><td id="amCodeOld">'+data.amCodeOld+'</td><td><input type="text" class="qty" id="amOldQty"/></td><td>'+data.amOldPrice+
'</td><td>'+data.am+
'</td><td>'+data.amCodeNew+'</td><td><input type="text" class="qty" id="amNewQty"/></td><td>'+data.amNewPrice+
'</td><td><input type="checkbox" id="amS" '+
'"/></td><td><input type="checkbox" id="amR"'+'"/></td><td><input type="checkbox" id="amCall"'+
'"/></td><td><input type="text" id="amComm" value="'+
'"/></td></tr>');
There are more rows like this one, each for a different guide I am using. What I need to find is the value of the inputs with id of amOldQty, amNewQty etc, and the different checkboxes.
I have buttons for Next, Prev, and Print, and when the button is clicked I am trying to call a function called save() that will get the info, and send it via ajax to another PHP page to be saved.
save() looks like this:
function save() {
var amOldQty
$('#guides tr').each(function(){
alert("searching ");
amOldQty= $(this).find('#amOldQty').val();
if (amOldQty=='' || amOldQty== null) {
amOldQty = "Not Showing Number";
}
console.log(amOldQty);
});// END OF EACH FUNCTION
I have tried:
var amOldQty;
$('#guides tbody tr').each(function() {
amOldQty = $(this).find('td:nth-child(1) input').val();
});
console.log(amOldQty);
and the log shows undefined. I have also tried a more direct approach by using
$('#guides tbody tr').each(function() {
amOldQty = $(this).find('#amOldQty').val();
});
and still have nothing. I am getting the alert of Searching, but in the console.log(amQtyOld) all it shows me is "Not Showing a number". I have even tried to have the input populated when the table first is created, and it still does not find that number.
Update if I add td to:
$(guides tr td).each(function(){...
It does not even give me the alert of "Searching".
How do I get all the data out of this table so I can save it? it seems that everything I am trying should be working.
If your users use browsers that support contenteditable elements, then you can check out the contenteditable widget I have available for my fork of tablesorter.
If you don't want to use contenteditable elements, then you can try the following code (copied and modified from the contenteditable demo, but not tested)
var $table = $('table');
$table.children('tbody').on('change', 'input', function(event){
var $input = $(this),
$cell = $input.closest('td'),
newContent = $input.val(),
cellIndex = $cell[0].cellIndex, // there shouldn't be any colspans in the tbody
rowIndex = $this.closest('tr').attr('id'); // unique row id
// update tablesorter
$table.trigger("updateCell", [$cell]);
$.post("mysite.php", {
"row" : rowIndex,
"cell" : cellIndex,
"content" : newContent
});
});
Hopefully, you're also using an input parser for that column.
The final answer seems to be to just hardcode the value of the inputs $("#amOldQty:).val() and pass them as data through ajax to my php file to save the information. Here is the completed code in case anyone has a similar issue:
function save() {
function GuidesSave(){
this.update();
}
GuidesSave.prototype.list = ['am','fol','tich','book','neb','ster','c','byte','ing'];
GuidesSave.prototype.update = function(){
for( var i = 0 ; i < this.list.length ; i++ ){
var guide = this.list[i];
this[ guide + 'S' ] = $("#" + guide+'S' ).is(":checked") ? 1 : 0;
this[ guide + 'R' ] = $("#" + guide+'R' ).is(":checked") ? 1 : 0;
this[ guide + 'Call' ] = $("#" + guide+'Call' ).is(":checked") ? 1 : 0;
}// end of for loop
}
var guides = new GuidesSave();
$.ajax({
type: "POST",
url: "poSave.php",
dataType: "json",
data: ({po: $('#po').val(),isbn:$("#isbn13").val(),amOldQty:$("#amOldQty").val(),amNewQty:$("#amNewQty").val(),amS:guides.amS,amR:guides.amR, amCall:guides.amCall,amComm:$("#amComm").val(),
folOldQty:$("#folOldQty").val(),folNewQty:$("#folNewQty").val(),folS:guides.folS,folR:guides.folR, folCall:guides.folCall,folComm:$("#folComm").val(),
tichOldQty:$("#tichOldQty").val(),tichNewQty:$("#tichNewQty").val(),tichS:guides.tichS,tichR:guides.tichR, tichCall:guides.tichCall,tichComm:$("#tichComm").val(),
bookOldQty:$("#bookOldQty").val(),bookNewQty:$("#bookNewQty").val(),bookS:guides.bookS,bookR:guides.bookR, bookCall:guides.bookCall,bookComm:$("#bookComm").val(),
nebOldQty:$("#nebOldQty").val(),nebNewQty:$("#nebNewQty").val(),nebS:guides.nebS,nebR:guides.nebR, nebCall:guides.nebCall,nebComm:$("#nebComm").val(),
sterOldQty:$("#sterOldQty").val(),sterNewQty:$("#sterNewQty").val(),sterS:guides.sterS,sterR:guides.sterR, sterCall:guides.sterCall,sterComm:$("#sterComm").val(),
cheggOldQty:$("#cOldQty").val(),cheggNewQty:$("#cNewQty").val(),cheggS:guides.cS,cheggR:guides.cR, cheggCall:guides.cCall,cheggComm:$("#cComm").val(),
byteOldQty:$("#byteOldQty").val(),byteNewQty:$("#byteNewQty").val(),byteS:guides.byteS,byteR:guides.byteR, byteCall:guides.byteCall,byteComm:$("#byteComm").val(),
ingOldQty:$("#ingOldQty").val(),ingNewQty:$("#ingNewQty").val(),ingS:guides.ingS,ingR:guides.ingR, ingCall:guides.ingCall,ingComm:$("#ingComm").val(),
qty1: $('#topqty').val(),price1: $('#topVal').html(),comp1:$('#topCo').html(),
qty2: $('#secqty').val(),price2: $('#secVal').html(),comp2: $('#secCo').html(),
qty3: $('#thrqty').val(),price3: $('#thrVal').html(),comp3: $('#thrCo').html()}),
success: function(data){
}
});
}// END OF SAVE FUNCTION
The GuideSave function loops through all the check boxes (27 different ones) to see whichones are checked so I can save them as either a 1 or 0 and then have them checked or not when the record is recalled.
It is not really clear what or how you are wanting to present the data. However, here is a JSFiddle that does what it appears you desire.
The function createRowsForTesting() just creates the rows in the table and populates the <input> fields to make testing easier.
The function getDataFromTable() walks the rows of a <table>, or all <tables>, sending the data you said you wanted to the console. From your own answer to this question it became clear that you really wanted to access many more <input> elements than was mentioned in your question. Thus, this this function now builds an array of Objects which contain key:value pairs for the data in <input> fields. There is one Object in the array for each row. The array is returned to the calling function.
The function wrapGetDataFromTable() wraps getDataFromTable() providing the table ID, that we are only looking in rows within the <tbody> tag and that we want output to the console. The array returned by getDataFromTable() is output so we can see the data structure. The function is set up to run each time you press the [print to console] button.
For a table that looks like (with header row):
The output is:
amOldQty=amOldQty0_text amNewQty=amNewQty0_text amS=on amR=off amCall=off amComm=amComm0_text
amOldQty=amOldQty1_text amNewQty=amNewQty1_text amS=off amR=on amCall=off amComm=amComm1_text
amOldQty=amOldQty2_text amNewQty=amNewQty2_text amS=off amR=off amCall=on amComm=amComm2_text
The array of row input data objects is:
[0] Object { amOldQty="amOldQty0_text", amNewQty="amNewQty0_text", amS="on", more...}
amOldQty: "amOldQty0_text"
amNewQty: "amNewQty0_text"
amS: "on"
amR: "off"
amCall: "off"
amComm: "amComm0_text"
[1] Object { amOldQty="amOldQty1_text", amNewQty="amNewQty1_text", amS="off", more...}
amOldQty: "amOldQty1_text"
amNewQty: "amNewQty1_text"
amS: "off"
amR: "on"
amCall: "off"
amComm: "amComm1_text"
[2] Object { amOldQty="amOldQty2_text", amNewQty="amNewQty2_text", amS="off", more...}
amOldQty: "amOldQty2_text"
amNewQty: "amNewQty2_text"
amS: "off"
amR: "off"
amCall: "on"
amComm: "amComm2_text"
JavaScript:
/**
* Runs through a table getting the values from <input> fields.
* It only looks in the <tbody>, not the <thead>
* #param tableId
* The DOM ID of the table from which we desire to obtain the
* input values.
* If tableId is not a string, then look in all table rows in all tables.
* #param keyAttr
* The attribute of the <input> which contains the value which will
* be used as the key for the key:value pair within the Object returned.
* This needs to be a value which is unique, wihin the table row.
* A normal use would be "id".
* If a value is duplicated a message is sent to the console and only
* the last value is kept.
* The default is "id".
* #param justBody
* If true, look only within the <tbody> tag, not any other part of
* the table (e.g. <thead>).
* The default is true.
* #param includeBlank
* Boolean indicating if the returned array should contain an entry for
* rows which are found to be blank.
* The default is true.
* #param consoleOutput
* Send a line to the console with the key:value pairs separated by
* tabs for each row.
* The default is false.
* #return Object
* Returns an Array of Objects with key:value pairs for the rows.
* If there were no <input>
* Copyright 2014 by Makyen.
* Released under the MPL 2.0. http://mozilla.org/MPL/2.0/.
*/
function getDataFromTable(tableId, keyAttr, justBody, includeBlank, consoleOutput) {
//This assumes that within the row each input has a unique attribute keyAttr.
//Set defaults:
var tableSelector = (typeof tableId === "string") ? "#" + tableId : "table";
keyAttr = (typeof keyAttr === "string") ? keyAttr : "id";
includeBlank = (typeof includeBlank === "boolean") ? includeBlank : true;
justBody = (typeof justBody === "boolean") ? justBody : true;
consoleOutput = (typeof consoleOutput === "boolean") ? consoleOutput : false;
var bodySelector = (justBody) ? " tbody" : "";
var toReturn = [];
var selector = tableSelector + bodySelector + ' tr';
$(selector).each(function () {
var inputs = {};
$(this).find('input').each(function () {
//Get the value for all inputs on this line.
var attrValue = $(this).attr(keyAttr);
if (typeof inputs[attrValue] !== "undefined") {
console.log("Warning: When attempting to get data from the table id=" //
+ tableId + " the value of the key attribute, " + keyAttr //
+ ", was not unique for value=" + attrValue);
}
//Get the value of the <input>.
if ($(this).is(':checkbox')) {
//Special case the checkboxes because .val() does not return
//the correct informaiton for them.
//First indicate that all checkboxes are off.
inputs[attrValue] = "off";
//Specifically determine if the current one is checked.
if ($(this).is(':checked')) {
inputs[attrValue] = "on";
}
} else {
//Add this input to the object
inputs[attrValue] = $(this).val();
}
});
var inputKeys = Object.keys(inputs);
if (inputKeys.length > 0) {
//There were <input> tags on this row.
var outputText = "";
if (consoleOutput) {
inputKeys.forEach(function (value) {
outputText += value + "=" + inputs[value] + "\t";
});
console.log(outputText);
}
toReturn.push(inputs);
} else {
//No <input> tags on this row
if (includeBlank) {
if (consoleOutput) {
console.log("A row without <input> tags was found.");
}
toReturn.push(inputs);
}
}
});
return toReturn;
}
function wrapGetDataFromTable() {
//This wraper is so the getDataFromTable() function remains
// generic. The wrapper merely defines which table from which to
// get the data,
// the attribute to use for unique keys = "id"
// to look only in the <tbody>
// to not include an object for the lines which are blank
// and output the row data to the console.
var toReturn = getDataFromTable("guides", "id", true, false, true);
if (typeof console.dir === "function") {
//Make sure console.dir() exists prior to using it.
console.log("The array of row input data objects is:");
console.dir(toReturn); //Let us see the Object in the console for checking.
}
return toReturn;
}
$('#to-console-button').click(wrapGetDataFromTable);
//The rest is setup for creating the table header and rows.
//It is only for testing.
function createRowsForTesting() {
const numRowsToCreate = 3;
var i;
var data = {
amCodeOld: "amCodeOld",
amOldPrice: "amOldPrice",
am: "am",
amCodeNew: "amCodeNew",
amNewPrice: "amNewPrice"
};
//Create the table
//First add a header.
$("#guides thead").append('<tr><th>amCodeOld_H</th>' //
+ '<th>amOldQty_H</th>' //
+ '<th>amOldPrice_H</th>' //
+ '<th>am_H</th>' //
+ '<th>amCodeNew_H</th>' //
+ '<th>amNewQty_H</th>' //
+ '<th>amNewPrice_H</th>' //
+ '<th>amS_H</th>' //
+ '<th>amR_H</th>' //
+ '<th>amCall_H</th>' //
+ '<th>amComm_H</th></tr>');
//Now the body rows.
for (i = 0; i < numRowsToCreate; i++) {
//From stackoverflow question: http://stackoverflow.com/questions/25998929/extract-data-from-a-tablesorter-table-with-javascript
$("#guides tbody").append('<tr><td id="amCodeOld">'+data.amCodeOld+'</td><td><input type="text" class="qty" id="amOldQty"/></td><td>'+data.amOldPrice+ //
'</td><td>'+data.am+ //
'</td><td>'+data.amCodeNew+'</td><td><input type="text" class="qty" id="amNewQty"/></td><td>'+data.amNewPrice+ //
'</td><td><input type="checkbox" id="amS" '+ //
'"/></td><td><input type="checkbox" id="amR"'+'"/></td><td><input type="checkbox" id="amCall"'+ //
'"/></td><td><input type="text" id="amComm" value="'+ //
'"/></td></tr>');
}
//*
//Fake having the table filled in, as I am tired of entering the input
//You have to try it without this, but with manual input in order to truly verify
var row = 0;
$('#guides tbody tr').each(function () {
$(this).find('#amOldQty').val("amOldQty" + row + "_text");
$(this).find('#amNewQty').val("amNewQty" + row + "_text");
$(this).find('#amComm').val("amComm" + row + "_text");
row++;
});
//*/
}
createRowsForTesting();
HTML:
<table class="tablesorter" id="guides">
<thead></thead>
<tbody></tbody>
</table>
<button type="button" id="to-console-button">print to console</button>
<!-- values to use to fill input:
amOldQty0_text
amOldQty1_text
amNewQty0_text
amNewQty1_text
amComm0_text
amComm1_text -->
Note: The selector ($("#guides").append('<tr>...) used in your line to add the table row to the table might be your problem. It currently adds your rows as the last elements in the <table>, not the last in the <tbody>. While the browser should compensate for this, it is possible that it is not doing so in your environment. Try $("#guides tbody").append('<tr>...
However, it appears more likely that the issue is a header row (or a row without input cells) in the <tbody>. The code now accounts for this possibility.
I have a view with a table with single selection mode and a button in its toolbar to delete selected row.
Though when I press the button, it deletes all the rows instead.
My code:
View file:
<template data-controller-name="myapplication.myview2">
<div data-sap-ui-type="sap.ui.table.Table" id="tb1" data-width="100%" data-title="Person Table"></div>
</template>
Controller File:
onInit: function() {
try {
var oTab = [
// the table content
];
var oToolbar = new sap.ui.commons.Toolbar();
oToolbar.addItem(new sap.ui.commons.Button({text: "Delete selected row",
press: function() {
try {
var newTab = this.getParent().getParent();
var index = newTab.getSelectedIndex();
if (index == -1)
alert("No row selected");
else {
var currModel = newTab.getModel();
var selectedRow = newTab.getRows()[index];
newTab.removeRow(selectedRow);
currModel.setData({table: newTab});
newTab.bindRows("/table");
}
} catch (err) {
txt = "There was an error on this page.\n\n";
txt += "Error description: " + err.message + "\n\n";
txt += "Click OK to continue.\n\n";
alert(txt);
}
}}));
this.byId("tb1").setToolbar(oToolbar);
this.byId("tb1").setVisibleRowCount(5);
this.byId("tb1").setNavigationMode(sap.ui.table.NavigationMode.Paginator);
// Columns definition should be HERE
var oModel = new sap.ui.model.json.JSONModel();
oModel.setData({table: oTab});
this.byId("tb1").setModel(oModel);
this.byId("tb1").bindRows("/table");
} catch (err) {
txt = "There was an error on this page.\n\n";
txt += "Error description: " + err.message + "\n\n";
txt += "Click OK to continue.\n\n";
alert(txt);
}
},
// More functions....
Any ideas please?
You need to remove row from model, not from table directly.
Here is an example on how to do this.
http://jsbin.com/yewula/1/edit
Like many folks have suggested, we should removed it from the model. Since table is binded to the model, table will refresh accordingly.
-D
In your press function for the delete button, get more details about the table:
var tableIndex = newTab.getSelectedIndex();
var context = newTab.getContextByIndex(tableIndex);
var path = context.getPath();
In the variable path you will then find the data index that corresponds to the table row index. Use this data index to remove the row from the model.
currModel.oData.table.splice(data_index, 1);
Afterwards, all that should be needed is a refresh of the model to inform the controls about the changed data. And, for the user it might also be nice if the selection in the table gets reset as well.
currModel.refresh();
newTab.setSelectedIndex(-1);
Below is a function where it controls whatever happens after a file has finished uploading in its own table row. Each table row consists of a file input where the user can upload a file and then the name of the file is appended within it's own table row.
If the upload was successful then it displays a successful message, if upload was not successful then it displays a message stating there is an error. But I also have another function within the function where the user can delete a file by clicking on the "Delete" button. The only problem I have is with this line of code:
$(".imagemsg" + counter).html(data);
Let's say that I have 2 table rows, and I delete a file in the first row, the message within .imagemsg should only be displayed in the first row as that was the row the deletion occured, it shouldn't display the message in the first and second row.
Another example is that if I have 4 table rows and I delete the file in the third row, then the message should be displayed in the 3rd row as that is where the deletion has occured.
So my question is what do I need to add to $(".imagemsg" + counter).html(data); so that the message is only displayed within the row the deletion of the file occured and not in all .imagemsg which is in every row?
Below is full code:
function stopImageUpload(success, imagefilename){
var result = '';
var counter = 0;
counter++;
if (success == 1){
result = '<span class="imagemsg'+counter+'">The file was uploaded successfully!</span><br/><br/>';
$('.listImage').eq(window.lastUploadImageIndex).append('<div>' + htmlEncode(imagefilename) + '<button type="button" class="deletefileimage" image_file_name="' + imagefilename + '">Remove</button><br/><hr/></div>');
}
else {
result = '<span class="imageemsg">There was an error during file upload!</span><br/><br/>';
}
$(".deletefileimage").on("click", function(event) {
var image_file_name = $(this).attr('image_file_name');
jQuery.ajax("deleteimage.php?imagefilename=" + image_file_name)
.done(function(data) {
$(".imagemsg" + counter).html(data);
});
$(this).parent().remove();
});
return true;
}
BELOW IS HTML CODE:
var $fileImage = $("<form action='imageupload.php' method='post' enctype='multipart/form-data' target='upload_target' onsubmit='return imageClickHandler(this);' class='imageuploadform' >" +
"Image File: <input name='fileImage' type='file' class='fileImage' /></label><br/><br/><label class='imagelbl'>" +
"<input type='submit' name='submitImageBtn' class='sbtnimage' value='Upload' /></label>" +
"</p><p class='listImage' align='left'></p>" +
"<iframe class='upload_target' name='upload_target' src='#' style='width:0;height:0;border:0px;solid;#fff;'></iframe></form>");
I believe that your counter variable will always be 1. So, all your span.imagemsg1 are the same. This is why you get the message in every row. Set the counter outside the function to increment the counter.
I believe that will stop the behavior that you are seeing, but I would like to give a shout out to the other answers as they are giving good advice to cleaning this code up.
Frankly, you should never use unique identifier in the class. Why not use an id or a data-image-count attribute?
In your html code you'll need to add a unique identifier, I would suggest using id. This way when you try to reference the element to add the error message in, it will only find one element. Currently it's looking for the first occurrence of the element with class = "imagemsg". You'll need a way to loop through each "row" and make the id's "imagemgs1", "imagemsg2", etc...Hope it helps.
It would be helpful to be able to see the HTML. Also, I cannot see in your script what you do with the "result" value. At this stage, I personally don't think there is enough info to help satisfactorily you yet.
However, an issue you will undoubtedly see is with your "counter" variable. Maybe that is your problem - hard to tell without the detail I asked for above. Your jQuery.ajax call will complete at some point but the value of "counter" may not be the same as when you called the jQuery.ajax() method. This is because the "counter" variable is being declared in a different scope.
E.g. Look at the code below. It sort of demonstrates your problem with the counter variable. It may look like at the end of 5 seconds it will spit out the numbers from 1 to 10 but it won't. It will spit out the value "10" ten times.
var x = 0;
for (var i = 0; i < 10; i++)
{
x++;
setTimeout(function() { console.log(x); }, 5000);
}
This problem applies to your code as well. You can fix the above by copying the variable value in to a variable of your local scope. E.g.:
var x = 0;
for (var i = 0; i < 10; i++)
{
var newScope = function() {
x++;
var y = x;
setTimeout(function() { console.log(y); }, 5000);
}();
}
Below is a function where it controls whatever happens after a file has finished uploading in its own table row. Each table row consists of a file input where the user can upload a file and then the name of the file is appended within it's own table row.
If the file was successful then it displays a successful message, if upload was not successful then it displays a message stating there is an error. But I also have another function within the function where the user can delete a file by clicking on the "Delete" button. The only problem I have is with this line of code:
$(".imagemsg").html(data);
Let's say that I have 2 table rows, and I delete a file in the first row, the message within .imagemsg should only be displayed in the first row as that was the row the deletion occured, it shouldn't display the message in the first and second row.
So my question is what do I need to add to $(".imagemsg").html(data); so that the message is only displayed within the row the deletion of the file occured and not in all .imagemsg which is in every row?
Below is full code:
function stopImageUpload(success, imagefilename){
var result = '';
if (success == 1){
result = '<span class="imagemsg">The file was uploaded successfully!</span><br/><br/>';
$('.listImage').eq(window.lastUploadImageIndex).append('<div>' + htmlEncode(imagefilename) + '<button type="button" class="deletefileimage" image_file_name="' + imagefilename + '">Remove</button><br/><hr/></div>');
}
else {
result = '<span class="imageemsg">There was an error during file upload!</span><br/><br/>';
}
$(".deletefileimage").on("click", function(event) {
var image_file_name = $(this).attr('image_file_name');
$(this).parent().remove();
jQuery.ajax("deleteimage.php?imagefilename=" + image_file_name)
.done(function(data) {
$(".imagemsg").html(data);
});
});
return true;
}
Pass the relevant element to the callback function. You already have $(this), so you can probably get the right row from that and put it in a variable, then access it in the callback to put the result in the right place.