Table row clickable using anchor element - javascript

I have a nodes table with 6 columns.
On the first column (named "Node id"), there is the index number for each node (each one on a different row). When I click on a specific index number, a modal window opens, containing the node's info.
When I created the table, I've made each node id an anchor element:
if (key[j] == "nodeid") {
var cell = document.createElement("td");
var aux = document.createElement("a");
Then, when a click a particular one, I call a function that gets the node's info from a server:
$("a").click(function(test) {
getEndpoints(test.target.innerHTML);//innerHTML= node id number
});
What I want to do, is to click anywhere on the row in order to open that modal window containing the information for the node displayed on that row.
What I've tried so far is to make every <td> and anchor element by redefining the if statement:
if (key[j]) {
var cell = document.createElement("td");
var aux = document.createElement("a");
cell.appendChild(aux);
var cellText = document.createTextNode(value[key[j]]);
aux.appendChild(cellText);
row.appendChild(cell);
The thing is, in order for this to work correct, I always have to click on the node index first in order to get the info. If I click anywhere else on the row first, the content i get is blank.
///LATER EDIT
Here is the getEndpoints function I use in order to get data for a particular node:
function getEndpoints(nodeid) {
$.get(".../iot/cmd/node/" + nodeid + "/class/mib/act/allS", function (node) {
window.data = node;
var key = ["epid", "clslist", "loc", "type", "zplus"];
var endpoints = node.endpoints[0];
for (var k = 0; k < key.length; k++) {
$("#" + key[k]).text(endpoints[key[k]]);
}
});
}
Then I populate this div with the data requested from getEndpoints:
<div id="endDiv" style="display: none">
<ol class="rounded-list">
<li><label>ID: <span id="name"></span></label></li>
<li><label>LOC. NAME: <span id="loc"></span></label></li>
<li><label>EPID: <span id="epid"></span></label></li>
<li><label>CLSLIST: <span id="clslist"></span></label></li>
<li><label>TYPE: <span id="type"></span> </label></li>
<li><label>ZPLUS: <span id="zplus"></span> </label></li>
</ol>
</div>
Then I put the div content in the modal window:
$("a").on( "click", function() {
$("#endDiv").contents().appendTo(".modal-content")
});

Related

Dynamically add rows that can be search-filtered from a list using JavaScript

I have a list of items, generated by PHP that is quite long. I don't want to show this list in a dropdown menu. Instead, I'm using jquery to have users type in a textbox, then filtering from that list based on user input:
Example HTML:
<table id = "table">
<tr>
<td>Select an animal:</td>
<td><input type="text" id = "animal" name="animal" placeholder="Choose an animal...">
<td id="animals">
<span class="animal_list">
<p onclick="insertme('horse')">Horse</p>
</span>
<span class="animal_list">
<p onclick="insertme('goat')">Goat</p>
</span>
<span class="animal_list">
<p onclick="insertme('sheep')">Sheep</p>
</span>
<span class="animal_list">
<p onclick="insertme('cow')">Cow</p>
</span>
</div>
</tr>
</table>
And the CSS to hide the list:
#animals .animal_list {
display: none;
}
JQuery filter:
$(document).ready(function(){
$('#animal').keyup(function() {
var search = this.value.split(';');
$('.animal_list').each(function(index, element) {
var text = $(element).text().toLowerCase();
var show = search.filter(function(e) {
return e != '' && text.indexOf(e.toLowerCase()) >= 0;
}).length > 0;
$(element).toggle(show);
});
});
});
And here's some JavaScript that allows users to click on the option to input it in the textbox:
function insertme(label){
document.getElementById('animal').value = label;
//when selected, hide all of variable 1 list
var list = document.getElementsByClassName("animal_list");
for (var i = 0; i < list.length; i++) {
list[i].style.display = "none";
};
}
This works great as is. However, for my application, the users need to be able to duplicate rows dynamically. My idea was to copy the html from the div (the "animals" div) and repeat it for every row:
function add_row(ID) {
var table = document.getElementById(ID);
var rowCount = table.rows.length;
var row = table.insertRow(rowCount);
// insert a row label
// insert a row label
var col1 = row.insertCell(0);
col1.innerHTML = "Select an animal:"
// second column...
// insert a search box
var col2 = row.insertCell(1);
var element = document.createElement("input");
element.type = "text";
element.name = "animal";
col2.appendChild(element);
// get the existing elements
var existing_list = document.getElementById("animals");
// create new object (so I can delete the first)
var list_copy = existing_list
// delete old list so it's not duplicating jquery effect across all rows
existing_list.remove();
//append list to new row
col2.appendChild(list_copy);
}
However, this doesn't seem to work. The second row doesn't filter based on the list anymore. According to my development console, the div does indeed get deleted from the first row, then inserted in the second row, but the list of items is not displaying based on user input. In other words, the JQuery filtering stops working at the second row.
Any ideas how to fix this? I'm happy to abandon my approach if there's a better way (i.e., better than copying a div to a new row and deleting the div associated with the original row).
(P.S. sorry for slovenly mixing JavaScript with JQuery. I'm a bit of a noob with both).
Putting it all together:
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script type="text/javascript">
function add_row(ID) {
var table = document.getElementById(ID);
var rowCount = table.rows.length;
var row = table.insertRow(rowCount);
// insert a row label
var col1 = row.insertCell(0);
col1.innerHTML = "Select an animal:"
// second column...
// insert a search box
var col2 = row.insertCell(1);
var element = document.createElement("input");
element.type = "text";
element.name = "animal";
col2.appendChild(element);
// get the existing elements
var existing_list = document.getElementById("animals");
// create new object (so I can delete the first)
var list_copy = existing_list
// delete old list so it's not duplicating jquery effect across all rows
existing_list.remove();
//append list to new row
col2.appendChild(list_copy);
}
function insertme(label){
document.getElementById('animal').value = label;
//when selected, hide all of variable 1 list
var list = document.getElementsByClassName("animal_list");
for (var i = 0; i < list.length; i++) {
list[i].style.display = "none";
};
}
$(document).ready(function(){
$('#animal').keyup(function() {
var search = this.value.split(';');
$('.animal_list').each(function(index, element) {
var text = $(element).text().toLowerCase();
var show = search.filter(function(e) {
return e != '' && text.indexOf(e.toLowerCase()) >= 0;
}).length > 0;
$(element).toggle(show);
});
});
});
</script>
<style type="text/css">
#animals .animal_list {
display: none;
}
</style>
</head>
<body>
<table id = "table">
<tr>
<td>Select an animal:</td>
<td><input type="text" id = "animal" name="animal" placeholder="Choose an animal...">
<td id="animals">
<span class="animal_list">
<p onclick="insertme('horse')">Horse</p>
</span>
<span class="animal_list">
<p onclick="insertme('goat')">Goat</p>
</span>
<span class="animal_list">
<p onclick="insertme('sheep')">Sheep</p>
</span>
<span class="animal_list">
<p onclick="insertme('cow')">Cow</p>
</span>
</div>
</tr>
</table>
<input type="button" onclick="add_row('table')" value = "Add Row">
</body>
</html>
The HTML for each row was incorrect.
Unclosed tags and hanging end tags. I've adjusted it so that the cells are consistent.
id must be unique, so I've changed it to be class="animals", which may be helpful in the future for DOM selection.
changed CSS style #animals -> .animals
It's important that each row is encapsulated, self-contained, and consistent so that DOM traversal can be done reliably. This allows for code related to each DOM node to be self-contained, so you can treat them like components. It will also help with CSS styling.
With this organization, all you have to do is cloneNode(true) the row to add a new one, and for the events traverse within the row to select the DOM nodes you need to target.
I've used Event Delegation to attach a single event to the table that targets every input[name="animals"] node inside it. So all new rows get targeted correctly.
Since all the DOM traversal and event handlers are self-contained for each row, the same event handler can be reused for all nodes.
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script type="text/javascript">
function add_row(ID) {
var table = document.getElementById(ID);
var rowCount = table.rows.length;
// (full) clone the last row and append to table
table.appendChild(table.rows[rowCount - 1].cloneNode(true))
}
function insertme(el, label) {
var row = $(el).closest('tr')
row.find('input[name="animal"]')[0].value = label;
//when selected, hide all of variable 1 list
var list = row[0].getElementsByClassName("animal_list");
for (var i = 0; i < list.length; i++) {
list[i].style.display = "none";
};
}
$(document).ready(function() {
// event delegation on table for all inputs with name "animal"
$('#table').on('keyup', 'input[name="animal"]', function(event) {
var search = this.value.split(';');
// traverse DOM to find containing row, then search for animal list nodes
$(this).closest('tr').find('.animal_list').each(function(index, element) {
var text = $(element).text().toLowerCase();
var show = search.filter(function(e) {
return e != '' && text.indexOf(e.toLowerCase()) >= 0;
}).length > 0;
$(element).toggle(show);
});
});
});
</script>
<style type="text/css">
.animals .animal_list {
display: none;
}
</style>
</head>
<body>
<table id="table">
<tr>
<td>Select an animal:</td>
<td><input type="text" name="animal" placeholder="Choose an animal..."></td>
<td class="animals">
<span class="animal_list">
<p onclick="insertme(this,'horse')">Horse</p>
</span>
<span class="animal_list">
<p onclick="insertme(this,'goat')">Goat</p>
</span>
<span class="animal_list">
<p onclick="insertme(this,'sheep')">Sheep</p>
</span>
<span class="animal_list">
<p onclick="insertme(this,'cow')">Cow</p>
</span>
</td>
</tr>
</table>
<input type="button" onclick="add_row('table')" value="Add Row">
</body>
</html>

How to find the current element index which is dynamically generated?

I have coded some simple function which allow me to add order. I have also dynamically created the button which when called will remove the current html element which is a table row. Now, I am stuck with finding the current element index which I needed so I can use splice to remove it from the array.
const order = [];
const customer = {
name: '',
totalCups: 0
}
$('#btnAdd').click(function() {
debugger
var itemName = $('#customerName');
var itemTotalCups = $('#customerTotalCups');
customer.name = itemName.val();
customer.totalCups = itemTotalCups.val();
// Data structure Queue
order.push(Object.assign({}, customer));
// UI - HTML rendering - start
if (order.length === 1) {
// Create table column name
$('#AllOrders').append('<table id="tbl" class="table table-bordered"><tr><td>Customer</td><td>Cups</td><td></td></tr></table>');
}
var itemElement = `<tr><td>${itemName.val()}</td><td>${itemTotalCups.val()}</td><td><a class='del' href='#'>Cancel order</a></td></tr>`;
$('#tbl').append(itemElement);
// UI - HTML rendering - end
$('.del').click(function(e) {
e.stopImmediatePropagation();
// Delete order object
debugger
//var elm = $(this).parent().text().substr(0, $(this).parent().text().length-1);
console.log(elm);
console.log(order.indexOf(elm));
//order.splice(order.indexOf(elm),1);
//order.splice(2,1);
// Delete HTML element
$(this).parent().parent().remove();
})
// Reset textbox
itemName.val("");
itemTotalCups.val("");
// Optional Design
$('#ViewAllOrders').click();
debugger;
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input id="customerName" type="text" />
<input id="customerTotalCups" type="number" />
<button id="btnAdd">Add</button>
<div id="AllOrders"></div>
I search for the solution but can't figure out the commented code below to find the element
//var elm = $(this).parent().text().substr(0, $(this).parent().text().length-1);
I am stuck inside $('.del').click event handler.
You can find the element in the order array by getting the index of the row where the clicked cancel button is.
To do so, you have to first get the current row. You can use the closest method:
var $row = $(this).closest('tr');
Now, you can get the index of the current row through the index method. You have to take into account that you have the tr for the header, you we need to substract one:
var index = $row.index() - 1;
Your final code should look like:
$('.del').click(function(e) {
e.stopImmediatePropagation();
var $row = $(this).closest('tr');
var index = $row.index() - 1;
order.splice(index, 1);
// Delete HTML element
$row.remove();
});
You can find the parent tr element and use that element to find the customer name and delete that node from DOM.
Couple of methods you want to try out:
.closest(): find the first match in the parent DOM hierarchy
https://api.jquery.com/closest
.filter(): filter an array based on some condition
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
So, basically you can find the closest tr node using closest and then find the customer name from within this tr's first td element.
Then, use filter on order to remove its instance from the order array.
Below is the changed code from the snippet:
$('.del').click(function(e) {
e.stopImmediatePropagation();
// Delete order object
var elm = $(this).closest('tr');
var nameToDelete = elm.find('td:first').text();
// filter out order
order = order.filter(item => item.name !== nameToDelete);
console.log('order now is = ', order);
// Delete HTML element
elm.remove();
});
More appropriately, learn about using HTML data-* Attributes along with id and class that could really ease up DOM manipulation. There are many samples online. Give that a try.
Cheers!
var order = [];
const customer = {
name: '',
totalCups: 0
};
$('#btnAdd').click(function() {
var itemName = $('#customerName');
var itemTotalCups = $('#customerTotalCups');
customer.name = itemName.val();
customer.totalCups = itemTotalCups.val();
// Data structure Queue
order.push(Object.assign({}, customer));
// UI - HTML rendering - start
if (order.length === 1) {
// Create table column name
$('#AllOrders').append('<table id="tbl" class="table table-bordered"><tr><td>Customer</td><td>Cups</td><td></td></tr></table>');
}
var itemElement = `<tr><td>${itemName.val()}</td><td>${itemTotalCups.val()}</td><td><a class='del' href='#'>Cancel order</a></td></tr>`;
$('#tbl').append(itemElement);
// UI - HTML rendering - end
$('.del').click(function(e) {
e.stopImmediatePropagation();
// Delete order object
var elm = $(this).closest('tr');
var nameToDelete = elm.find('td:first').text();
// filter out order
order = order.filter(item => item.name !== nameToDelete);
console.log('order now is = ', order);
// Delete HTML element
elm.remove();
});
// Reset textbox
itemName.val("");
itemTotalCups.val("");
// Optional Design
$('#ViewAllOrders').click();
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input id="customerName" type="text" />
<input id="customerTotalCups" type="number" />
<button id="btnAdd">Add</button>
<div id="AllOrders"></div>

Show a table (number of rows variable) on a div after click button? Works until some point

(This is my first question here and I am new to programming)
I am stuck on a problem and I tried to take something from here:
http://jsfiddle.net/4pEJB/
Dynamically generated table - using an array to fill in TD values
The function I created receive two vectors and creates a table with 2 columns, one for each vector, and lines = vector.length.
The function works fine, it seems to create the table as I need, but it doesn't show the table created on the browser screen after button click. By using some 'alert()' on the for loops I was able to verify that it uses the correct data.
In fact, when the button is clicked, it calls another function that processes some data and passes two vectors on this function I am showing here, but this part works well.
Here is the HTML part:
<div class="tableDiv">
<input type="button" onclick="createtable([1,3,5,7,9],[2,4,6,8,10])" value="Show data">
</div>
And here is the JavaScript part:
function createtable(vet_1,vet_2){
var tableDiv = document.getElementById("tableDiv");
var table = document.createElement("table");
var tableBody = document.createElement('tbody');
for (var r=0;r<vet_1.length;r++){
var row = document.createElement("tr");
for (var c=0;c<2;c++){
var cell = document.createElement("td");
if (c==0){cell.appendChild(document.createTextNode(vet_1[r]));}
else if(c==1){cell.appendChild(document.createTextNode(vet_2[r]));}
row.appendChild(cell);
}
tableBody.appendChild(row);
}
tableDiv.appendChild(table);
}
When the function finishes the table feed, it stops on tableDiv.appendChild(table);
Any advice or suggestions will be greatly appreciated! (I speak portuguese, I am sorry for some errors)
EDIT: it's possible to avoid the increment on the number of table rows that occurs every time we click the button (the solution provided generates one new table under the previous table). To solve this, I just added this line on the beggining of the function code (need to put the button outside the div and let the div empty, otherwise it will hide the button):
document.getElementById("tableDiv").innerHTML = "";
you are capturing by id, but you set up a class.chang it to id
<div id="tableDiv">
and append the tableBody into table.You're populating the table body with rows, but never appended the body into the table element.
function createtable(vet_1,vet_2){
var tableDiv = document.getElementById("tableDiv");
var table = document.createElement("table");
var tableBody = document.createElement('tbody');
for (var r=0;r<vet_1.length;r++){
var row = document.createElement("tr");
for (var c=0;c<2;c++){
var cell = document.createElement("td");
if (c==0){cell.appendChild(document.createTextNode(vet_1[r]));}
else if(c==1){cell.appendChild(document.createTextNode(vet_2[r]));}
row.appendChild(cell);
}
tableBody.appendChild(row);
}
table.appendChild(tableBody) // append tableBody into the table element
tableDiv.appendChild(table);
}
<div id="tableDiv">
<input type="button" onclick="createtable([1,3,5,7,9],[2,4,6,8,10])" value="Show data">
</div>
You try to append the var table to the tableDiv but the var table is stil empty.
Before append the tableBody to the var table and it will work.
Use id instead of class in your HTML Markup
<div id="tableDiv">
and then use the following code.
function createtable(vet_1,vet_2){
var tableDiv = document.getElementById("tableDiv");
var table = document.createElement("table");
var tableBody = document.createElement('tbody');
for (var r=0;r<vet_1.length;r++){
var row = document.createElement("tr");
for (var c=0;c<2;c++){
var cell = document.createElement("td");
if (c==0){cell.appendChild(document.createTextNode(vet_1[r]));}
else if(c==1){cell.appendChild(document.createTextNode(vet_2[r]));}
row.appendChild(cell);
}
tableBody.appendChild(row);
}
table.appendChild(tableBody);
tableDiv.appendChild(table);
}
First you are accessing the div using id whereas the node is defined with a class.
Secondly, you have to append the body to the table node first, and then append the table to the div selected.
Try this code snippet to move on.

LocalStorage and adding li to list

I'm trying to make a small script that allows for a little notes section. This section would have an input box that allows for adding elements to the list; which will be saved in localStorage so they are not lost when I refresh or close the browser. The code I have is as follows (it's all done through JS even the html, but ignore that.)
var notes = [];
var listthings = "<h2 id=\"titlething\">Notes</h2>" +
"<ul id=\"listing\">" +
"</ul>"
"<input type=\"text\" name=\"item\" id=\"textfield\">" +
"<input type=\"submit\" id=\"submitthing\" value=\"Submit\">";
JSON.parse(localStorage.getItem('notes')) || [].forEach( function (note) {
"<li id=\"listitem\">" + notes + "</li>";
})
$('#submitthing').click(function() {
notes.push($('#textfield').val());
});
localStorage.setItem('notes', JSON.stringify(notes));
Also, how would I go about appending the latest added li between the opening and closing tag? Obviously I'd usually do it using jQuery, but this is puzzling me a little. However, only the 'Notes' loads at the top, any ideas?
Your approach is way off the mark. You don't need JSON at all (this just confuses things) and you don't need to manually create HTML.
Also, you can use an array to store the notes, but since localStorage is the storage area, so an array is redundant. Additionally, without using an array, you don't need JSON. The entire problem becomes much easier to solve.
Unfortunately, the following won't run here in this snippet editor, due to security issues, but it would do what you are asking. This fiddle shows it working: https://jsfiddle.net/Lqjwbn1r/14/
// Upon the page being ready:
window.addEventListener("DOMContentLoaded", function(){
// Get a reference to the empty <ul> element on the page
var list = document.getElementById("notes");
// Loop through localStorage
for (var i = 0; i < localStorage.length; i++){
// Make sure that we only read the notes from local storage
if(localStorage.key(i).indexOf("note") !== -1){
// For each item, create a new <li> element
var item = document.createElement("li");
// Populate the <li> with the contents of the current
// localStorage item's value
item.textContent = localStorage.getItem(localStorage.key(i));
// Append the <li> to the page's <ul>
list.appendChild(item);
}
}
// Get references to the button and input
var btn = document.getElementById("btnSave");
var note = document.getElementById("txtNote");
// Store a note count:
var noteCount = 1;
// When the button is clicked...
btn.addEventListener("click", function(){
// Get the value of the input
var noteVal = note.value;
// As long as the value isn't an empty string...
if(noteVal.trim() !== ""){
// Create the note in localStorage using the
// note counter so that each stored item gets
// a unique key
localStorage.setItem("note" + noteCount, noteVal);
// Create a new <li>
var lstItem = document.createElement("li");
// Set the content of the <li>
lstItem.textContent = noteVal;
// Append the <li> to the <ul>
list.appendChild(lstItem);
// Bump up the note counter
noteCount++;
}
});
});
<input type=text id=txtNote><input type=button value=Save id=btnSave>
<ul id=notes></ul>
This is how I would approach it using jquery. but depens how complex this should be. this is just simple demo.
<input type="text" id="note" />
<button id="add">add note</button>
<ul id="notes"></ul>
javascript and jquery
function addNote(){
var data = localStorage.getItem("notes")
var notes = null;
if(data != null)
{
notes = JSON.parse(data);
}
if(notes == null){
notes = [];
}
notes.push($("#note").val());
localStorage.setItem("notes", JSON.stringify(notes));
refreshNotes();
}
function refreshNotes(){
var notesElement =$("#notes");
notesElement.empty();
var notes = JSON.parse(localStorage.getItem("notes"));
for(var i = 0; i< notes.length; i++){
var note = notes[i];
notesElement.append("<li>"+note+"</li>");
}
}
$(function(){
refreshNotes();
$("#add").click(function(){
addNote();
});
})
example:
http://codepen.io/xszaboj/pen/dOXEey?editors=1010

Javascript-Collapsing and expanding table rows based on hierarchy

I have the following table generated by a cgi script:
<table>
<tr id='vfipbb'><td>col 1,0</td><td>col 1,1</td></tr>
<tr id='vfipbb.alipbb'><td>col 2,0</td><td>col 2,1</td></tr>
<tr id='vfipbb.esipbb'><td>col 3,0</td><td>col 3,1</td></tr>
<tr id='vfipbb.esipbb.esipbb_madrid'><td>col 4,0</td><td>col 4,1</td></tr>
<tr id='vfipbb.esipbb.esipbb_barcelona'><td>col 5,0</td><td>col 5,1</td></tr>
</table>
This is just a sample of what it would look like, but the important bit to note is the id.
when the webpage first loads all rows are collapsed except for the root context (vfipbb). I want to enable functionality when the root context is clicked it will expand all child rows listed under this, for example (alipbb), (esipbb) and if one of the child rows is clicked it will expand all grandchildren rows, for example (esipbb_madrid) (esipbb_barcelona).
Is there any efficient way of doing this in javascript based on ID? Any pointer in the right direction would be greatly welcome!
Not a working code, but something to get you started
// add click handlers to all tr
var tr0 = document.getElementsByTagName("tr");
for (var i = 0; i < tr0.length; i++) {
tr0[i].addEventListener("click", openChild);
}
function openChild() {
var id = this.id;
//regex that matches a string beginning with
//the id followed by dot and some other words
var regex = new RegExp("^" + id + ".[a-z_]+$", "g");
var tr1 = document.getElementsByTagName("tr");
//browse through the tr(s)
for (var i = 0; i < tr1.length; i++) {
//Learn regex test function!
if (regex.test(tr1[i].id)) //if a match found
//display children
document.getElementById(tr1[i].id).style.visibility = "visible";
}
}

Categories

Resources