Problem: I have a small function that moves a row to the next one and back inside a table, it's in jQuery and I need it in JavaScript. Since I pretty much always work with jQuery and don't have the time to figure it out I would really appreciate it if somebody could help me do it.
I tried something like this but again I don't have the time and need it fast:
for (var i = 0; i < document.getElementsByClassName('up').length; i++) {
document.getElementsByClassName('up')[i].addEventListener('click',
function() {
let trFirst = document.getElementsByTag('tr:first');
let row = document.this.parentNode;
});
}
Solution would be this in JavaScript:
$(document).ready(function () {
$(".up,.down").click(function () {
var row = $(this).parents("tr:first");
if ($(this).is(".up")) {
row.insertBefore(row.prev());
} else {
row.insertAfter(row.next());
}
});
});
I understand that I need to learn this and can't use code I fully understand but like I said I need it quick and I know for some of you guys it's just a couple minutes work. Thanks a lot for taking the time!
function parentTr(element) {
let parent = element.parentNode;
while(parent != null) {
if(parent.nodeName === "TR") {
return parent;
}
parent = parent.parentNode;
}
}
let table = document.getElementById('table');
Array.from(document.getElementsByClassName('up')).forEach(upButton => {
upButton.addEventListener('click', function () {
let currentTr = parentTr(upButton);
let previousTr = currentTr.previousElementSibling;
if(previousTr) {
previousTr.parentNode.insertBefore(currentTr, previousTr);
}
});
});
Array.from(document.getElementsByClassName('down')).forEach(downButton => {
downButton.addEventListener('click', function () {
let currentTr = parentTr(downButton);
let nextTr = currentTr.nextElementSibling;
if(nextTr) {
currentTr.parentNode.insertBefore(nextTr, currentTr);
}
});
});
<table border="1" id="table">
<tr>
<td>row 1</td>
<td>
<button class="up">Up</button>
<button class="down">Down</button>
</td>
</tr>
<tr>
<td>row 2</td>
<td>
<button class="up">Up</button>
<button class="down">Down</button>
</td>
</tr>
<tr>
<td>row 3</td>
<td>
<button class="up">Up</button>
<button class="down">Down</button>
</td>
</tr>
</table>
Related
I want to remove one specific row from the list in tbody after clicking on the delete button. Could you help me figure out how to make it work with plain javascript?
I always get the error message "cannot get / a".
function updateUI() {
var tbody = document.getElementById('entry-table');
for (var i = 0; i < Storedcontact.length; i++) {
var entry = Storedcontact[i];
var row = document.createElement("tr");
row.innerHTML = `
<td>${entry.name}</td>
<td>${entry.surname}</td>
<td>${entry.phone}</td>
<td>${entry.email}</td>
<td>Delete</td>
<td>Edit</td>
`;
tbody.appendChild(row);
function clearFields() {
document.getElementById("name").value = "";
document.getElementById("surname").value = "";
document.getElementById("phone").value = "";
document.getElementById("email").value = "";
}
clearFields();
}
}
tbody.addEventListener("click", function(ev) {
ev.preventDefault()})
function removeContact(event) {
if (event.classList.contains("delete")) {
event.parentElement.parentElement.remove();
}
}
So basically you weren't that far. Here how you can do that:
const btns = document.querySelectorAll('table td button'); // the delete buttons
for (let i=0; i < btns.length; i++) { // you can use the modern forEach but this is faster
btns[i].addEventListener('click', function() { // trigger event when hitting each button:
this.closest('tr').remove(); // remove the line
});
}
<table>
<tr><td>line1 </td> <td> more </td> <td> <button>remove</button></td></tr>
<tr><td>line2 </td> <td> more </td> <td> <button>remove</button></td></tr>
<tr><td>line3 </td> <td> more </td> <td> <button>remove</button></td></tr>
<tr><td>line4 </td> <td> more </td> <td> <button>remove</button></td></tr>
<tr><td>line5 </td> <td> more </td> <td> <button>remove</button></td></tr>
</table>
You can read more about remove() on MDN
and on closest() too.
Enjoy Code!
Be aware, closest() is not supported in IE. Here's a function that mimics its functionality for your purposes:
function closestParent(element, tagName){
try{
while(element.tagName != tagName.toUpperCase()) element = element.parentNode;
return element;
}
catch(e){
return null;
}
}
I like using inline javascript for this sort of thing, keeps it simple and easy to read.
Delete</td>
I gather that you want to delete them onclick? execute this code after all rows have loaded in the page:
var trs = document.getElementsByTagName("tr");
for(var i = 0; i < trs.length; i++){
trs[i].addEventListener("click", function(){
this.outerHTML = "";
});
}
I was trying to build my first search function for a phonelist. Unfortunately it looks like, my filter function loops only trough the last column of the table.
Did i miss something? Or do i have to use a different approach for this?
PS: Pardon for the possible duplicate. All examples that i've found has been for PHP.
Many thanks in advance!
const phonelist = document.querySelector('table');
const searchInput = document.querySelector('#search');
const searchResult = document.querySelector('#search-result');
const searchValue = document.querySelector('#search-value');
// EVENTS
function initEvents() {
searchInput.addEventListener('keyup', filter);
}
function filter(e) {
let text = e.target.value.toLowerCase();
console.log(text);
// SHOW SEARCH-RESULT DIV
if (text != '') {
searchValue.textContent = text;
searchResult.classList.remove('hidden');
} else {
searchResult.classList.add('hidden');
}
document.querySelectorAll('td').forEach((row) => {
let item = row.textContent.toLowerCase();
if (item.indexOf(text) != -1) {
row.parentElement.style.display = 'table-row';
console.log(row.parentElement);
} else {
row.parentElement.style.display = 'none';
}
})
}
// ASSIGN EVENTS
initEvents();
<input id="search" />
<div class="phonelist">
<div id="search-result" class="hidden">
<p>Search results for <b id="search-value"></b>:</p>
</div>
<table class="striped">
<thead>
<tr>
<th>Phone</th>
<th>Fax</th>
<th>Room</th>
<th>Name</th>
<th>Title</th>
</tr>
</thead>
<tbody>
<tr>
<td>165</td>
<td>516</td>
<td>1.47</td>
<td>Johnathan Doe</td>
<td>Sales</td>
</tr>
<tr>
<td>443</td>
<td>516</td>
<td>1.47</td>
<td>Jane Dow</td>
<td>Development</td>
</tr>
</tbody>
</table>
</div>
it looks like you are querying the wrong element
document.querySelectorAll('td').forEach((row) => {
I think you want to be querying the row
document.querySelectorAll('tr').forEach((row) => {
otherwise you are of overriding your class changes with whatever is the result of the last column
(and obviously apply the class on the tr and not the parent of the tr)
Your code is actually going through all the elements but the changes from last column are overriding changes from previous columns.
Let's say you searched for dow, 2nd row 4th column is matched and shows the parent but after that your loop goes to 2nd row 5th column which doesn't match and hides the parent row.
I have updated your code, as shown below you should loop through the rows, check if any of its columns are matching and update the row only once based on the result.
const phonelist = document.querySelector('table');
const searchInput = document.querySelector('#search');
const searchResult = document.querySelector('#search-result');
const searchValue = document.querySelector('#search-value');
// EVENTS
function initEvents() {
searchInput.addEventListener('keyup', filter);
}
function filter(e) {
let text = e.target.value.toLowerCase();
console.log(text);
// SHOW SEARCH-RESULT DIV
if (text != '') {
searchValue.textContent = text;
searchResult.classList.remove('hidden');
} else {
searchResult.classList.add('hidden');
}
document.querySelectorAll('tr').forEach(row => {
let foundMatch = false;
row.querySelectorAll('td').forEach(col => {
let item = col.textContent.toLowerCase();
foundMatch = foundMatch || item.indexOf(text) > -1;
});
if (foundMatch) {
row.style.display = 'table-row';
} else {
row.style.display = 'none';
}
});
}
// ASSIGN EVENTS
initEvents();
<input id="search" />
<div class="phonelist">
<div id="search-result" class="hidden">
<p>Search results for <b id="search-value"></b>:</p>
</div>
<table class="striped">
<thead>
<tr>
<th>Phone</th>
<th>Fax</th>
<th>Room</th>
<th>Name</th>
<th>Title</th>
</tr>
</thead>
<tbody>
<tr>
<td>165</td>
<td>516</td>
<td>1.47</td>
<td>Johnathan Doe</td>
<td>Sales</td>
</tr>
<tr>
<td>443</td>
<td>516</td>
<td>1.47</td>
<td>Jane Dow</td>
<td>Development</td>
</tr>
</tbody>
</table>
</div>
I've got a search box where as I type, table data gets filtered through and only matching results get shown. It works great; however, I want to make it better.
I want the code to ignore spaces and dashes. I'd prefer make it easy to add additional characters I want it to ignore as well in the future..
For instance...
Product Table
FH-54
TDN 256
TDN25678
FH54
In the search box, if I type FH54, I'd like both the FH-54 and the FH54 to show up. If I type in FH-54 I'd also like the FH54 and the FH-54 to show up and so on to include FH 54 as well.
If I type in TDN2 or TDN 2 in the search box, I'd like TDN 256 and TDN25678 to show up.
<b>Product Search</b><br /><form class="formatted">
<input id="Search" data-class="search_product" type="text" /></form>
<script type="text/javascript">
$('#Search').on('keyup', function(e) {
$("#noData").remove();
var value = $(this).val();
value = value.replace(/\\/g, '');
var patt = new RegExp(value, "i");
var sw = 0;
var counter = 0;
$('#Data tbody').find('tr').each(function() {
counter++;
if (!($(this).find('td').text().search(patt) >= 0)) {
$(this).not('#header').hide();
sw++;
} else if (($(this).find('td').text().search(patt) >= 0)) {
$(this).show();
}
});
if (sw == counter) {
$("#Data tbody").append(`<tr id="noData">
<td colspan="3">No data</td>
</tr>`);
} else {
$("#noData").remove();
}
});
</script>
I've tried to reconstruct your scenario the best I could and made a working example.
As per your requirement to ignore all spaces and dashes: How about removing spaces and dashes from search string and from your values within the columns?
$('#Search').on('keyup', function(e) {
$("#noData").remove();
var value = $(this).val();
var spacesAndDashes = /\s|-/g;
value = value.replace(spacesAndDashes, "");
var patt = new RegExp(value, "i");
var sw = 0;
var counter = 0;
$('#Data tbody').find('tr').each(function() {
counter++;
if (!($(this).find('td').text().replace(spacesAndDashes, "").search(patt) >= 0)) {
$(this).not('#header').hide();
sw++;
} else if (($(this).find('td').text().replace(spacesAndDashes, "").search(patt) >= 0)) {
$(this).show();
}
});
if (sw == counter) {
$("#Data tbody").append(`<tr id="noData">
<td colspan="3">No data</td>
</tr>`);
} else {
$("#noData").remove();
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<b>Product Search</b>
<br />
<form class="formatted">
<input id="Search" data-class="search_product" type="text" />
</form>
<table id="Data">
<thead>
<tr>
<th>Product Table</th>
</tr>
</thead>
<tbody>
<tr>
<td>FH-54</td>
</tr>
<tr>
<td>TDN 256</td>
</tr>
<tr>
<td>FH54</td>
</tr>
<tr>
<td>FH 54</td>
</tr>
<tr>
<td>TDN25678</td>
</tr>
</tbody>
</table>
I have a table with check box for each row .
I need to remove the rows for the selected check boxes in the table on a button click. (this button is outside ng-repeat).
The index of the selected rows are populated to an array using ng-change function but i'm unable to remove the selected rows on a single button click
Here is the Fiddle
HTML
<div ng-app="approvalApp">
<div ng-controller="SimpleApprovalController" >
<table style="width:90%" border="5" >
<tr>
<th><input type="checkbox" ng-model="CheckAllData" ng- change="selectAll()" /></th>
<th>Date</th>
<th>AssociateID</th>
<th>Check-In</th>
<th>Checkout</th>
</tr>
<tr data-ng-repeat="approval in approvalitems">
<td><input type="checkbox" value="{{approval.ReqId}}" data-ng-model="approval.selected" data-ng-change="SelectDeselect($index)"/></td>
<td>{{approval.Date}}</td>
<td>{{approval.AssociateID}}</td>
<td>{{approval.CheckIn}}</td>
<td>{{approval.Checkout}}</td>
</tr>
</table>
<input type="button" value="Approve" data-ng-model="ApproveIndex" data-ng-click="ApproveRequest()" />
Script
$scope.SelectDeselect=function(index)
{
$scope.getIndexvalues = [];
angular.forEach($scope.approvalitems, function (approval,index) {
if (!!approval.selected) {
$scope.getIndexvalues.push(index);
$scope.CheckAllData = false;
}
});
console.log($scope.getIndexvalues);
};
$scope.ApproveRequest = function () {
$scope.selectedIdsArray = [{}];
angular.forEach($scope.approvalitems, function (item) {
if (!!item.selected) {
$scope.selectedIdsArray.push({ Reqid: item.ReqId, Status: "Approved" });
$scope.CheckAllData = false;
}
});
};
};
So how to use getIndexvalues in approverequest function , or is there any better way to remove it using other angular directive.
I'm a newbie to angular js .
Fiddle: http://jsfiddle.net/jpk547zp/1/
$scope.ApproveRequest = function () {
$scope.selectedIdsArray = [{}];
$scope.approvalitemsNew = [];
angular.forEach($scope.approvalitems, function (item) {
if (!!item.selected) {
$scope.selectedIdsArray.push({ Reqid: item.Date, Status: "Approved" });
$scope.CheckAllData = false;
item.hideThis = true;
console.log($scope.selectedIdsArray);
} else {
$scope.approvalitemsNew.push(item);
}
});
$scope.approvalitems = $scope.approvalitemsNew;
$scope.getIndexvalues = [];
};
Hope this helps.
you can simply do
$scope.ApproveRequest = function () {
$scope.approvalitems = $scope.approvalitems.filter(function(i){
return !i.selected;
});
};
Please, give "direction where to go"
Many input rows. For each row is field class="row_changed"
If value in the field is higher than 0, then ajax pass entire row to php. Each row is included in <tr> </tr> For each <tr> id is set <tr id='row'>
At the moment I can do it only with many if
Need something like: if value in any of field field class="row_changed" is more than 0, then pass corresponding row (inside <tr id='row'>) to php.
Here is some information. Is it suitable for the described case?
<tr id='row1'>
<td>
<input type="text" name="row1[]" id="date_day1" class="row_changed1">
</td>
...
<td>
<input type="text" name="row1[]" id="is_row_changed1" size="1">
<script>
$(".row_changed1").on("change", function () {
document.getElementById('is_row_changed1').value = 1;
});
</script>
</td>
<tr>
if ($("#is_row_changed1").val() > 0) {
$.post("_autosave_array.php", $("#row1 :input").serialize(), function (data1) {
$('#load1').html(data1);
$('#is_row_changed1').val(0)
});
var str = $("#row1 :input").serialize();
$("#load1_1").text(str);
}
if ($("#is_row_changed2").val() > 0) {
$.post("_autosave_array.php", $("#row2 :input").serialize(), function (data2) {
$('#load2').html(data2);
$('#is_row_changed2').val(0)
});
var str = $("#row2 :input").serialize();
$("#load2_1").text(str);
}
Something like this should do it:
function doPost(changedRowId,serializeRowId,resultId,serializeResultId){
if ($(changedRowId).val() > 0) {
$.post("_autosave_array.php", $(serializeRowId + ":input").serialize(), function (data2) {
$(resultId).html(data2);
$(changedRowId).val(0)
});
var str = $("#row2 :input").serialize();
$(serializeResultId).text(str);
}
var rowData = [{changedRowId: "#is_row_changed1", serializeRowId: "#row1", resultId: "#load1", serializeResultId: "#load1_1"},
{changedRowId: "#is_row_changed2", serializeRowId: "#row2 ", resultId: "#load2". serializeResultId: "#load2_1"}
];
for(var i = 0; i < rowData.length; ++i){
var data = rowData[i];
doPost(data.changedRowId,data.serializeRowId,data.resultId,data.serializeResultId);
}
I can see that all your input tags have the same name, you can select all of them by name then put your condition/logic inside
sample:
$("input[name='row1[]']").each(function(){
if($(this).val()>0){
$.post("_autosave_array.php", $("#row1 :input").serialize(), function (data1) {
$('#load1').html(data1);
$('#is_row_changed1').val(0)
}
});