Hi this is a second part to an early question. I need to add rows to a form consisting of a selection box. Each row of the form is a type of "Room" in a house and the user has to be able to add as many rooms as needed. I have it all working however if you fill in the 2nd room and then add a 3rd room it resets the selection box to its default for the 2nd room. I can see why it is doing this i just cant think of how to change the function so it keeps your previous selections intact. Note: i have the 1st row for the 1st room written in the HTML then this function(below) is called from a button click and adds the extra rooms.
function add_room() {
var room_count = 0;
write = document.getElementById('new_room')
var roomSelect = '<select name="level[]" id="levels"' + room_count + '/> ';
roomSelect += '<option>Basement</option>';
roomSelect += '<option>Lower Level</option>';
roomSelect += '<option>Main Floor</option>';
roomSelect += '<option>2nd Floor</option>';
roomSelect += '<option>3rd Floor</option></select>';
write.innerHTML += roomSelect;
room_count++;
}
Thanks for any help you can offer!
This is because of the magic of .innerHTML +=.
As you might have guessed, It's actually identical to div.innerHTML = div.innerHTML + moreHTML - So the browser resets the HTML of the div. Including any selection, obviously.
I'd recommend you used div.appendChild. It doesn't change previously loaded HTML, and so won't change the user's selection.
function add_room() {
var room_count = 0;
write = document.getElementById('new_room');
var roomSelect = document.createElement('select'); // create select node
roomSelect.setAttribute("name", "level[]");
roomSelect.setAttribute("id", "levels" + room_count);
roomSelect.innerHTML = '<option>Basement</option>'+ //set the innerHTML (the options)
'<option>Lower Level</option>'+
'<option>Main Floor</option>'+
'<option>2nd Floor</option>'+
'<option>3rd Floor</option>'
write.appendChild(roomSelect); //append the child
room_count++;
}
Related
I'm working on a personal project and I've run into an issue that I haven't been able to solve.
Here is a function that generates new table rows into a table (with id of "tableData") when a button is clicked:
function addNewRow(){
var tableEl = document.getElementById("tableData");
var newLine = '<tr class="newEntry">';
var classArray = ["classA", "classB", "classC", "classD"];
for (var i = 0; i < classArray.length; i++){
newLine += '<td><input class="' + classArray[i] + '"></td>';
}
newLine += '</tr>';
tableEl.insertAdjacentHTML("beforeend", newLine);
}
document.getElementById("addRow").addEventListener("click", addNewRow, false);
//the element with id="addRow" is a button
I've simplified the code for the above function for the sake of readability as it's not the focus of the problem. When the button is clicked, a new row is added successfully.
The problematic part involves another function that takes the sum of the respective classes of each row and displays them in a div.
The goal is to get the sum of the values of all input fields with matching class names. For example, let's say I use the addNewRow function to get six rows. Then I want to have the div showing the sum of the values of all input fields with the class name of "classA"; the number in that div should be the sum of those six values, which gets updated as I type in the values or change the existing values in any of the input fields with class name of "ClassA".
function sumValues(divId, inputClass){
var sumVal = document.getElementsByClassName(inputClass);
var addedUp = 0;
for (var j = 0; j < sumVal.length; j++){
addedUp += Number(sumVal[j].value);
}
document.getElementById(divId).innerHTML = addedUp;
}
Here are a couple (out of several) failed attempts:
document.input.addEventListener("keyup", sumValues("genericDivId", "classA"), false);
document.getElementsByClassName("classA").onkeyup = function(){sumValues("genericDivId", "classA");}
Unfortunately, after scouring the web for a solution and failing to find one, I just added an event listener to a button that, when clicked, would update the div to show the sum of values. Also had to modify the sumValues function to take values from an array rather than accepting arguments.
My question is: How can I modify the code so that the sum value updates as I type in new values or change existing values using pure Javascript (vanilla JS)?
You are very close, document.getElementsByClassName() returns an array of DOM objects, you need to set the onkeyup function for each and every element by looping through that array.
var classA = document.getElementsByClassName('classA'); // this is an array
classA.forEach(function(elem){ // loop through the array
elem.onkeyup = function(){ // elem is a single element
sumValues("genericDivId", "classA");
}
}
Hopefully this fixes your issue
Maybe the example below is not same with your situation, but you'll get the logic, easily. Anyway, do not hesitate to ask for more guide.
document.getElementById("row_adder").addEventListener("click", function() {
var t = document.getElementById("my_table");
var r = t.insertRow(-1); // adds rows to bottom - change it to 0 for top
var c = r.insertCell(0);
c.innerHTML = "<input class='not_important_with_that_way' type='number' value='0' onchange='calculate_sum()'></input>";
});
function calculate_sum() {
var sum = ([].slice.call(document.querySelectorAll("[type=number]"))).map(e=>parseFloat(e.value)).reduce((a, b) => a+b);
document.getElementById("sum").innerHTML = sum;
}
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<div>
<p>
<strong>Sum</strong>:<span id="sum">0</span>
</p>
</div>
<button id="row_adder">
Click me
</button>
<table id="my_table">
</table>
</body>
</html>
I was trying to make a code that when you introduce a table row (clicking on a button) it use the first cell from the row as name of a cookie. That's fine, at least atm.
My problem is that when i try to delete a row from that table I want to delete the cookie that is associated with that, not that hard, but i'm not really sure what am i doing wrong.
Thanks!
http://jsfiddle.net/roucher/d9h6onvr/
function borrarTR() {
document.getElementById("tablaPaseadores").deleteRow(0);
contador--;
var x = document.getElementById("tablaPaseadores").rows.length;
var celda = "celda" + x + "1";
alert(celda);
var cname = document.getElementById(celda).innerHTML;
alert(cname + "1");
deleteCookie(cname);
It dosent alert that last alert: "(cname + "1")" So I guess the problem is in celda, but celda returns the right value.
EDIT: Solved.
I had 2 errors: first and main one, if i try to get the id of something that has been already deleted, it will obviously return null.
And second, I should have realised also that the lenght in from [1-i] and I am working from [0-i-1] so i had to do this to solve both:
function borrarTR() {
var x = (document.getElementById("tablaPaseadores").rows.length)-1;
var celda = "celda" + x + "1";
var cname = document.getElementById(celda).innerHTML;
document.getElementById("tablaPaseadores").deleteRow(0);
contador--;
deleteCookie(cname);
}
I'm creating a dynamic menu that fetches dishes from a database and displays them to the user so he can add them to his order. Whenever I retrieve a row from the database I send it to my menuItems class so the columns can be read and the display format is created and inserted into a cell:
foreach (DataRow dr in drc){
//extract the dish data from the row into a cell
TableCell c1 = menuItem.makeItemCell(dr);
//display it
tr.Controls.Add(c1);
table1.Controls.Add(tr);
}
c1 will be a cell that has the dish information along with a quantity dropdownlist and an "add to order" button:
public static TableCell makeItemCell(DataRow dr)
{
TableCell tc = new TableCell();
Image img = new Image();
img.ImageUrl = (string)dr["img"];
tc.Controls.Add(img);
//rest of information adding is omitted for brevity
String myLiteral = "<p>" + "Name: " + (string)dr["NameofDish"] + "</br>";
tc.Controls.Add(new LiteralControl(myLiteral));
//add quantity label and dropdownlist populated with possible quantity values
Label lb = new Label();
lb.Text = "Quantity: ";
DropDownList ddl = new DropDownList();
for (int i = 0; i < 13; i++)
{
String t = i.ToString();
ddl.Items.Add(new ListItem(t, t));
}
//create the add to order button
Button btn = new Button();
btn.Text = "Add to order";
tc.Controls.Add(lb);
tc.Controls.Add(ddl);
tc.Controls.Add(btn);
return tc;
}
My problem is with handling the button click event. All my tries to bind it with an event handler (on the menuItems class or the codebehind itself) have failed. I could only manage to update the postbackURL of the button when it's created in the cell like this
btn.PostBackUrl = "./menu.aspx?dish=" + (string)dr["ID"] + "&quantity=" + ddl.SelectedValue;
But the .selectedvalue value is rendered when the cell is created hence is always 0
My question is this: how can I handle the button click event in a way that I can get hold of the dishID and the selected value.
((((I would prefer an event handling solution rather than querystrings if possible))))
Thank you!
EDIT:
My whole problem is that the cell and its components are created in the external class and sent back to my code. How do I access the dropdownlist variable from my codebehind if I don't have the element id or anything
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);
}();
}
I have a report populated as a table with a stringbuilder from the codebehind. The first TD of every row is a checkbox, the id of each checkbox is assigned dynamically:
sb.Append("<td><input type='checkbox' id='chkSelectAll_" + i + "' name='chk_" + i + "' onclick='JavaScript: chkAll_click(this);' /> </td>"
The aspx page uses a master page and
<asp:Content><div id='divMain'></div></asp:Content>
format other than a form to populate. The problem I am running in to is that I am having trouble finding all the elements (or any actually) of the div to work with. Here is the javascript I have been given. (Team project at work, I was just assigned 1 task on the project so changing anything is not an option.)
function divBatchBuild_click() {
debugger
var form = document.forms[0];
var visitList = '';
for (i = 0; i < form.elements.length; i++) {
if (form.elements[i].type == 'checkbox') {
//alert(form.elements[i].id.toString());
if (form.elements[i].checked == true &&
form.elements[i].id != 'chkSelectAll') {
var y = form.elements[i].id;
//alert('id=' + y[1].toString());
visitList = visitList + y[i].toString() + '|';
}
}
}
}
Apparently this worked on a previous project, but when used with this report the process never goes inside the if statement. Any help on what is going wrong is appreciated.
I think you want to first get the div, then get the elements in the div with the checkbox tagname. Something like:
var div = document.getElementById('divMain');
var elements = div.getElementsByTagName('checkbox');
for (i = 0; i < elements.length; i++) {