I have an HTML table I am adding columns to dynamically. Each input column added also has a check mark to continue adding it and an x mark to remove it. The remove function is not working as I am trying to remove the closest td but then all of the added input columns are removed when I click on the x mark. How do I make it so just the selected dynamic column is removed? Here is what I have
var myform = $('#myform'),
iter = 0;
$('#btnAddCol').click(function () {
myform.find('tr').each(function(){
var trow = $(this);
if(trow.index() === 0){
trow.append('<td><input type="text" id="input"><input type="image" src="checkmark.png" name="accept" class="accept" id="accept" /><input type="image" src="xmark.png" name="cancel" class="cancel" id="cancel" /></td>');
}
});
iter += 1;
});
$('#cancel').click(function () {
$(this).closest("td").find('.input').remove();
});
Based on your code you seem to be appending a cell(TD element) to a table row(TR) of the table.
To remove the cell (or any element within that cell) you can pass the element(this) that was clicked to a function like this:
<input type="button" value="cancel" id="cancel" onClick="removeCell(this)" />
and then define a new function that will remove the parent element(the TD element in this case) or a different element within the cell like this:
function removeCell(clickedElement) {
// select the parent element(td element) of the cancel button, and remove it
$(clickedElement.parentElement).remove();
}
Demo
Related
This is simple java class that has a list of strings for example:
public class Apple {
private List<String> listOfStrings;
// getters setters
}
html with thymeleaf:
<form method="post" th:object="${apple}"> // apple is set through Model.addAttribute(.., ..) in Controller
<input type="text" th:each="str, iter : *{listOfStrings} th:field="*{listOfStrings[__${iter.index}__]}">
<button id="add" type="button" onclick="add()>Add</button>
<button id="remove" type="button" onclick="remove()">Remove</button>
<input type="submit" value="Save">
<form>
javascript add and remove new input:
const newInputTextString="<input type=\"text\" th:field="?">" // th:field won't be evaluated/bound to apples listOfStrings index
function add() {
const xhttp = new XMLHttpRequest();
xhttp.onload = function() {
document.getElementById("add").insertAdjacentHTML("beforebegin", newInputTextString);
}
xhttp.open("GET", window.location.href);
xhttp.send();
}
function remove() {
// TODO
}
So far I am only adding html through javascript, but I can not include th: tags there since these tags wont be evaluated and bind to specific object or fields.
Expected functionality:
on click of remove button, last input of type text that is bound to specific index of listOfStrings is removed.
on click of add button, new input of type text is added and bound to next index of listOfStrings.
In other words I want to make user able to remove and add strings in listOfStrings of that apple object with html buttons.
Feel free to correct my English
th:field essentially just gives you an ID and a NAME attribute on an element. You cannot add a th:field through JS but you can emulate its behavior by manually adding the appropriate ID and NAME attributes. With that said you should make some slight changes in your HTML and JS code.
You should always have a record of the current total number of strings so you can adjust your string index. For that I've created a div wrapper around all string inputs so we can access it in JS. Afterwards we just read the number of elements inside of it and create a new index out of it.
You can look the implementation below:
function createInput(index) {
var input = document.createElement('input');
input.setAttribute('type', 'text');
input.setAttribute('id', `listOfStrings[${index}]`);
input.setAttribute('name', `listOfStrings[${index}]`);
input.setAttribute('placeholder', `listOfStrings[${index}]`);
input.setAttribute('data-index', index);
input.setAttribute('data-input', '');
return input;
}
function addString() {
var inputsWrapper = document.querySelector('[data-inputs]');
var inputs = inputsWrapper.querySelectorAll('[data-input]');
var newIndex = inputs.length;
var newInput = createInput(newIndex);
inputsWrapper.append(newInput);
}
<form method="post" th:object="${apple}">
<div style="display: flex; flex-direction: column; max-width: 300px" data-inputs>
<input
type="text"
placeholder="listOfStrings[0]"
th:placeholder="${'listOfStrings[__${iter.index}__]'}"
th:each="str, iter : *{listOfStrings}"
th:attr="data-index=${__${iter.index}__}"
th:field="*{listOfStrings[__${iter.index}__]}"
data-input />
</div>
<button id="add" type="button" onclick="addString()">Add</button>
<button id="remove" type="button" onclick="remove()">Remove</button>
<input type="submit" value="Save">
<form>
Clearing child div inside parent div, there are many answers like :
$(".ChildDiv").html("");
$('.ChildDiv > div').remove();
$(".ChildDiv").html("");
$("#ParentDiv").html("");
$(".ChildDiv div").remove();
$(".ChildDiv div").empty();
$('.ChildDiv ').find('div').remove();
Probably I have listed all possible way to remove the div's, but even after using all these, I still not able to clear all the div's inside Parent Div. let me explain what I am doing and what I need.
Scenario :
I have two container-1, one of the container has input search box, where I can search for entering employee name and select few employees Ex. 5 and can use "Add" button to move those employees to the other container-2 which is 'div'.
Now I click on report button event and get the information of those 5 people in different aspx, now if i go back to the page where i have to search for another 3 employees and when I again click on the "Add" button, it should add only 3 employees instead it is adding last searched 5 + 3 employees!!.
So i am trying to clear the 5 employees inside that div after i click on "Report" button , when i use alert() it says it has 0 element, but when I add it for the second time, it appends the data again, which i dont need. here is the code :
Points to remember :
1. ParentDiv is the container-2
2. ChildDiv is the child div inside ParentDiv(which is dynamically appended when we select 5 employees on "Add" button click"
Here is the code:
HTML :
<table id="topTable">
<tr>
<td id="leftpane">
<h4>Search for Employee by Name or Profile:</h4>
<input type="text" id="EmployeeSearchBox" class="search-box" aria-multiselectable="true" />
<select id="EmployeeList" size="20" multiple></select>
</td>
<td id="centerpane">
<div> <input type="button" value="Add >>" class="AddButton" id="buttonAdd" /></div>
<div> <input type="button" value="Add All >>" class="AddButton" id="buttonAddAll" /></div>
</td>
<td id="rightpane">
<h4>Selected Employees:</h4>
<div id="ParentDiv"></div>
</td>
</tr>
</table>
Run Report button event
<input class="data" type="submit" name="cmdSubmit" value="Run Report" onclick="return FormValidate();"
onserverclick="RunReport" runat="server" id="Submit1" />
Add Button Click :
which moves the employees from container-1 to container-2.
$(document).on('click', '#buttonAdd', function (e) {
$('#EmployeeList :selected').each(function (i, selected) {
myHash[$(selected).val()] = $(selected).text();
});
var myNode = $("#ParentDiv")[0];
while (myNode.firstChild) {
myNode.removeChild(myNode.firstChild);
}
for (var emp_id in myHash) {
var emp = $("#ParentDiv").append("<div class= ChildDiv id=" + emp_id + ">" + myHash[emp_id] + " <span class='close'>×</Span> </div>");
}
$('#EmployeeSearchBox').val("").trigger('input');
});
On click of "Report" button it should clear all the elements from ParentDiv/ChildDiv which is what I did, but still it is not clearing it, how can I resolve/remove these elements once "Report" button event clicked.
Here is a sample of "Report" button event :
function FormValidate() {//Part of my other code
$(".ChildDiv").html("");
$('.ChildDiv > div').remove();
$(".ChildDiv").html("");
$("#ParentDiv").html("");
$(".ChildDiv div").remove();
$(".ChildDiv div").empty();
$('.ChildDiv ').find('div').remove();
}
None of them is working, i feel there is an issue with the "Add" button event, where it is storing the data.
NOTE :
I don't want to clear the array of employee list, since I want to select multiple employees again again Ex. I can select 2 employees starts with the letter "M" and I can search the 2 employees of letter "L" and add those 2 employees, the container should hold 4 employees before "Report" button click.
Let me know if I am clear enough.
Console Log
Finally I could able to fix the issue, i was facing, I am posting the answer, now it is working as I need.
$(document).on('click', '#buttonAdd', function (e) {
var div_count = $('#ParentDiv').find('div').length;
if (div_count === 0) {
myHash = []; // Clearing the hash, so that it can add fresh employees, if count == 0 in container- 2.
$('#EmployeeList :selected').each(function (i, selected) {
myHash[$(selected).val()] = $(selected).text();
});
}
else { // If there are existing employees in container-2 then append few more.
$('#EmployeeList :selected').each(function (i, selected) {
myHash[$(selected).val()] = $(selected).text();
});
}
var myNode = $("#ParentDiv")[0];
console.log(myNode);
while (myNode.firstChild) {
myNode.removeChild(myNode.firstChild);
}
for (var emp_id in myHash) {
var emp = $("#ParentDiv").append("<div class= ChildDiv id=" + emp_id + ">" + myHash[emp_id] + " <span class='close'>×</Span> </div>");
}
$('#EmployeeSearchBox').val("").trigger('input');
});
What I did
Since I should be able to append multiple employees by searching, that is handled in 'else' part, if I generated the "Report" then, I am clearing the Container-2.
When I come back to page to search few more employees, by this time Container-2 will not be having any employees, so
var div_count = $('#ParentDiv').find('div').length;
if (div_count === 0) {
myHash = [];
//....
}
will clear the array which allow me to add fresh employees, hence it solved my problem :)
Thanks all for the support.
Edited to adjust on comments:
You need to clear the myHash variable. Otherwise employees will be added again from there.
I have html elements as:
<input type=hidden class=txtCustomerId value=".parent::current()." />";
<input type=button class=printToTextarea value='Get to box' />
and jquery:
$(".printToTextarea").on("click", function () {
var array = $('.txtCustomerId').map(function() {
return this.value;
}).get();
loadxmldoc(array);
});
It passing all elements as array from hidden field with class name txtCustomerId while I need only current element when button click. Button is also array and both should have same index.
The following code using eq() and index() meet the requirement at much extent.
$(".printToTextarea").on("click", function () {
var i = $('.printToTextarea').index(this);
var custid=$('.txtCustomerId').eq(i).val();
loadxmldoc(custid);
$("#textInput").focus();
});
Change:
$('.txtCustomerId')
to:
$(this).prev('.txtCustomerId')
Well you are selecting all of the elements. So you need to select the one that is related. With your example, you would use prev() to get a reference to the element.
$(".printToTextarea").on("click", function () {
var button = $(this);
var inputValue = button.prev(".txtCustomerId").val();
console.log(inputValue);
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type=hidden class=txtCustomerId value="hello" />
<input type=button class=printToTextarea value='Get to box' />
But how you get the input really depends on your HTML. So if the structure is different than the two elements beside each other, than the way to select it would change.
I have a HTML-JavaScript script in which the user can insert data to a new array [] by using a form's text field and an insert button.
By pressing insert button, the user inserts the data typed into the array.
I have a function which prints all the values of the array into <p id="demo"></p> and runs itself every 100 milliseconds in order to be updated with the arrays values.
I also have a reset button to delete every array's value when clicked.
What I want to do is add a delete button next to each array's value in order to be easier for the user to delete the wrong value he inserted.
I am using this code to insert values and print them:
HTML:
<div align="center">
<form id="form1">
<input type="text" name="fname" id="fname" placeholder="Type here!">
</form>
<br>
<input type="button" id="Button Insert" onclick="myFunction()" value="Insert">
<input type="button" onclick="myFunction3()" value="Reset">
</div>
<p id="demo" align="center"></p>
JavaScript/JQuery:
var all_values =[];
function myFunction() {
var temp_val = $("#fname").val();
all_values.push(temp_val);
document.getElementById("form1").reset();
}
setInterval(function () {
$("#demo").html(all_values.join("<br>"));
}, 100);
function myFunction3() {
all_values.length = 0;
}
To be more specific I want something like these things: iOS example JSFiddle Example 1 JSFiddle Example 2.
Could you please help me? Thanks in advance.
I'd do it the other way around.
Remove setInterval as it's really bad way to do such things.
Remove white spaces from the id attribute (id="Button-Insert", not id="Button Insert")
Don't use onclick attributes. Instead, register click event handlers with jQuery
// caching is a good practice when you reffer to the same elements multiple times:
var all_values =[], demo = $("#demo"), form = $("#form1")[0], fname = $("#fname");
$('#Button-insert').click(function(){
var temp_val = fname.val();
all_values.push(temp_val);
// create delete button along with the value
demo.append('<p>'+temp_val+' <button value="'+temp_val+'" type="button" class="del-btn">Delete</button></p>');
form.reset();
});
$('#Button-reset').click(function(){
all_values = [];
demo.html('');
});
// event delegation for dynamic elements:
demo.on('click', '.del-btn', function(){
all_values.splice(all_values.indexOf($(this).val()), 1);
$(this).parent().remove();
});
JSFiddle
Simply create the delete buttons at the same time you create the table.
function loadvalues(){
var i, button;
$('#demo').empty();
for(i in all_values){
$('#demo').append(all_values[i]);
button = $('<button>',{'text':'Delete'}).click(function(){
all_values.splice(this,1);
loadvalues();
}.bind(i)).appendTo('#demo');
$('#demo').append('<br>');
}
}
Also you don't need to poll, you could simply add each one on demand with a function like this:
function addVal(){
var val = $("#fname").val(), i = all_values.length;
all_values.push(val);
$('#demo').append(val);
button = $('<button>',{'text':'Delete'}).click(function(){
all_values.splice(this,1);
loadvalues();
}.bind(i)).appendTo('#demo');
$('#demo').append('<br>');
}
I had some typos, the code works,
Check here:
http://codepen.io/anon/pen/QbvgpW
I have a table(1) with checkbox against each row. When i click a checkbox its value is shown in another table(2). In table(2) each row has a remove option. If i click remove, the row will be removed. In the same way if i uncheck the checkbox in table(1), the corresponding row in table(2) should be removed.So how should i remove a row on uncheck.I have placed this part of code in else block.
$(document).ready(function(){
$('.isSelected').click(function() {
var pdtname = $(this).attr('data-productname');
if ( $('.isSelected:checked').length > 0) {
$("#result").show();
var table = $('<table></table>').addClass('tfoo');
var row = $('<tr></tr>').addClass('rfoo').text(pdtname);
var link = $('<a href="javascript:void(0);">/a>').addClass('lfoo').text('Remove');
row.append(link);
table.append(row);
$('#result').append(table);
$("#result").on('click','.lfoo',function(){
$(this).parent().parent().remove();
});
} else {
$('.isSelected[data-productname="pdtname"]').on('click','.lfoo',function(){
$(this).parent().parent().remove();
});
}
});
});
HTML
<div id="result" ></div>
<td><form method='post' action='<c:url value="compareproducts.html"/>' >
<input class="isSelected" type="checkbox" name='id' value='${product.id}'
data-productname="${product.productName}" >
</form>
As per our conversation in the chat. A quick solution would be to add a data-productname to the table so when you uncheck a checkbox, it removes the table with the same data-productname (notice that for this to work, the productname must be unique).
You can see an example on this jsfiddle: http://jsfiddle.net/4g8nL9t5/1/