I want to achieve the below two scenarios:
Need to add rows on click of the plus button.
Need to replace the plus button with a hyperlink from the dynamically added rows.
<button type="button" class="addRow" />+</button>
Replace the above button with the below for all the dynamically added rows.
Remove
I've done the first scenario and stuck with the second one.
HTML:
<table id="exampleTbl">
<tr>
<td>1</td>
<td>2</td>
<td>
<button type="button" class="addRow" />+</button>
</td>
</tr>
<tr>
<td>3</td>
<td>4</td>
<td>
<button type="button" class="addRow" />+</button>
</td>
</tr>
</table>
jQuery:
$(function() {
$('#exampleTbl').delegate('button.addRow', 'click', function() {
var row = $(this).closest('tr'); // get the parent row of the clicked button
var html = $(this).closest('tr').clone();
$(html).insertAfter(row); // insert content
});
});
You could try this.
$(function() {
$('#exampleTbl').delegate('button.addRow', 'click', function() {
var row = $(this).closest('tr'); // get the parent row of the clicked button
var html = $(this).closest('tr').clone();
$(html).insertAfter(row); // insert content
let btn = $('Remove');
btn.click(function () {
$(html).remove(); // Remove row on click
})
$(html).find('.addRow').replaceWith(btn);
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="exampleTbl">
<tr>
<td>1</td>
<td>2</td>
<td>
<button type="button" class="addRow">+</button>
</td>
</tr>
<tr>
<td>3</td>
<td>4</td>
<td>
<button type="button" class="addRow">+</button>
</td>
</tr>
</table>
Working JSFiddle: https://jsfiddle.net/j18yfwLv/1/
Note: I just replaced the button with the content you wanted, do you want the button to remove the row as well?
Related
I am trying to write a simple product management program. Basically, when users input a product name, it will be saved to an array and displayed on the table using a for loop.
I am having trouble with my codes here. It shows duplicate each time I click add a product. For example, the 1st time I add productA, it shows productA. The second time I add productB, it shows productA, productA, productB (duplicate productA).
I know the problem is within the loop I use, but have no idea how to fix.
I cannot paste HTML code here, but here is the link to my codes. https://github.com/minhle0105/functionPractice/tree/main/productManagement
Thanks everyone
You were displaying products array instead of the new product, that's what it was displaying the whole array.
TRY This
<!DOCTYPE html>
<html>
<head>
<title>Product List Management</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<p>Add New Product</p>
<div class="add_product">
<input type="text" name="productAdd" id="productAdd" placeholder="New Product">
<button type="button" id="addbtn" onclick="addProductToList()">Add</button>
</div>
<p>Display All Products</p>
<div class="productDisplay" id="productDisplay">
<table class="table">
<thead>
<tr>
<th style="text-align: left; background-color: white;">Product Names</th>
</tr>
</thead>
<tbody id="result">
</tbody>
</table>
</div>
<script>
let products = [];
let count = 0;
function addProductToList() {
let productAdd = document.getElementById("productAdd").value;
products.push(productAdd);
document.getElementById("result").innerHTML ="";
displayProduct(products)
}
function displayProduct(products) {
for(let i=0; i<products.length; i++){
document.getElementById("result").innerHTML +=`<tr>
<td>${i+1}</td>
<td>${products[i]}</td>
<td><button type="button" class="btn edit">Edit</button></td>
<td><button type="button" class="btn delete">Delete</button></td>
</tr>
`
}
}
</script>
</body>
</html>
Something like this
let products = [];
let count = 0;
function addProductToList() {
let productAdd = document.getElementById("productAdd").value;
products.push(productAdd);
document.getElementById("productAdd").value=''; document.getElementById("result").innerHTML ="";
displayProduct(products)
}
function displayProduct(products) {
for (var i = 0; i < products.length; i++) {
document.getElementById("result").innerHTML +=`<tr>
<td>${products[i]}</td>
</tr>
`
}
}
<div class="add_product">
<input type="text" name="productAdd" id="productAdd" placeholder="New Product" required>
<button type="button" id="addbtn" onclick="addProductToList()">Add</button>
</div>
<div class="productDisplay" id="productDisplay" style="margin-top: 15px;">
<table class="table">
<thead>
<tr>
<th>Product</th>
</tr>
</thead>
<tbody id="result">
</tbody>
</table>
</div>
I'm trying to export a painted html table completely dynamically into a csv file. I tried to implement several Scripts, functions.etc but I have not obtained the desired result. If anyone can help me, I'd be very grateful.
The information in the table is loading from a Request in "jsonData", It is important to clarify that I do not require to know the "Headers", only the information inside the table body:
ts Code:
jsonData:any;
_object = Object;
"jsonData" looks like:
[{
Subject_ID: "ACCT101",
First_Available_Date: "01/01/01",
....
},
{
Subject_ID: "510862185-X",
First_Available_Date: "06/04/19"..}....
]
HTML
<table>
<thead>
<tr>
<th *ngFor="let header of _object.keys(jsonData[0]); let i = index">{{header}}</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let row of jsonData; let i = index">
<td *ngFor="let objKey of _object.keys(row); let j = index">{{ row[objKey] }} </td>
</tr>
</tbody>
</table>
<button class="btn btn-submit btn-sm float-right" type="submit" (click)="export()">
Submit
</button>
Please try below code. this will extract data from table and download as csv.
<!DOCTYPE html>
<html>
<head>
<style>
td, table,th{
border: solid 1px black;
}
</style>
</head>
<body>
<table id="data_table">
<thead>
<tr>
<th>Subject_ID</th>
<th>First_Available_Date</th>
</tr>
</thead>
<tbody>
<tr>
<td>ACCT101</td>
<td>01/01/01</td>
</tr>
<tr>
<td>510862185-X</td>
<td>06/04/19</td>
</tr>
<tr>
<td>New data</td>
<td>New data 1</td>
</tr>
</tbody>
</table>
<script>
function exportit() {
var csv='';
table=document.getElementById("data_table");
tr=table.children[0].children[0];
for(i=0;i<tr.children.length;i++)
{
csv+=tr.children[i].innerText+",";
}
csv=csv.substring(0,csv.length-1)+"\n";
tbody=table.children[1];
for(i=0;i<tbody.children.length;i++)
{
for(j=0;j<tbody.children[i].children.length;j++)
{
csv+=tbody.children[i].children[j].innerText+",";
}
csv=csv.substring(0,csv.length-1)+"\n";
}
csv=csv.substring(0,csv.length-1)+"\n";
var hiddenElement = document.createElement('a');
hiddenElement.href = 'data:text/csv;charset=utf-8,' + encodeURI(csv);
hiddenElement.target = '_blank';
hiddenElement.download = 'data.csv';
hiddenElement.click();
}
</script><br>
<button onclick="exportit()">export</button>
</body>
</html>
I have an MVC Application that returns items from the model and there is a button added on the table to each row, the problem is that only the first item that is working perfectly the rest doesn't even call the method. I have done my research with no luck. here is the code on my view. is there something that I am doing wrong? Please help.
<section class="container">
<section class="panel">
<section class="panel-heading panel-border-danger ">
<h2 class="panel-heading-text ">
<i></i> Script Management
</h2>
</section>
<link href="~/Content/Site.css" rel="stylesheet" />
<section >
<table class="table table-responsive" id="tblScripManager">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.scriptName)
</th>
<th>
#Html.DisplayNameFor(model => model.logFileName)
</th>
<th>
#Html.DisplayNameFor(model => model.Active)
</th>
<th>
#Html.DisplayNameFor(model => model.AllowToRun)
</th>
<th>
#Html.DisplayNameFor(model => model.scriptdescription)
</th>
<th> Last Run </th>
<th> Time Taken</th>
<th> Errors </th>
<th> Re-Run </th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.scriptName)
</td>
<td>
#Html.DisplayFor(modelItem => item.logFileName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Active)
</td>
<td>
#Html.DisplayFor(modelItem => item.AllowToRun)
</td>
<td>
#Html.DisplayFor(modelItem => item.scriptdescription)
</td>
<td>
#Html.DisplayFor(modelItem => item.lastRun)
</td>
<td>
#Html.DisplayFor(modelItem => item.timeTaken)
</td>
#if (item.Errors == "No Errors")
{
<td>#Html.DisplayFor(modelItem => item.Errors)</td>
}
else
{
<td style="cursor:pointer"> <a id="myBtn" class="btn-group">#Html.DisplayFor(modelItem => item.Errors)</a></td>
}
<td>
<input id="btnRun" type="button" value="Run Script" onclick="location.href='#Url.Action("Script", "RunScript")?id=' + document.getElementById('#item.scriptId').value" />
</td>
</tr>
<div id="myModal" class="modal">
<!-- Modal content -->
<div class="modal-content" style="padding-top: 10px; padding-left: 10px; padding-right:30px; left: 50px; top: 70px; width: 70%; height: 50%; ">
<span class="close">×</span>
<p style="line-break:strict">#Html.DisplayFor(modelItem => item.ErrorList)</p>
</div>
</div>
}
</tbody>
</table>
</section>
</section>
</section>
<script>
$(document).ready(function () {
$("#btnRun").click(function () {
$.getJSON('#Url.Action("RunScript")', { scriptId: '4' }, function (data) {
console.log(data);
//$("#run").val(data);
});
});
});
// Get the modal
var modal = document.getElementById('myModal');
// Get the button that opens the modal
var btn = document.getElementById("myBtn");
// Get the <span> element that closes the modal
var span = document.getElementsByClassName("close")[0];
// When the user clicks the button, open the modal
btn.onclick = function () {
modal.style.display = "block";
}
// When the user clicks on <span> (x), close the modal
span.onclick = function () {
modal.style.display = "none";
}
// When the user clicks anywhere outside of the modal, close it
window.onclick = function (event) {
if (event.target == modal) {
modal.style.display = "none";
}
}
$('.modal').click(function () {
$('#my-dialog').load(this.href, function () {
$(this).dialog('open');
});
return false;
});
</script>
`
The button id is not unique. Generate a unique id like with the below and it should be ok.
I would also invoke the post using Jquery and css selector.
var itemCount = 0;
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.scriptName)
</td>
<td>
#Html.DisplayFor(modelItem => item.logFileName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Active)
</td>
<td>
#Html.DisplayFor(modelItem => item.AllowToRun)
</td>
<td>
#Html.DisplayFor(modelItem => item.scriptdescription)
</td>
<td>
#Html.DisplayFor(modelItem => item.lastRun)
</td>
<td>
#Html.DisplayFor(modelItem => item.timeTaken)
</td>
#if (item.Errors == "No Errors")
{
<td>#Html.DisplayFor(modelItem => item.Errors)</td>
}
else
{
<td style="cursor:pointer"> <a id="myBtn" class="btn-group">#Html.DisplayFor(modelItem => item.Errors)</a></td>
}
#{var buttonid = "btnRun" + itemCount};
<td>
<input id="#buttonid" type="button" class="MyButton" value="Run Script" data-scriptid="#item.scriptId"/>
</td>
</tr>
<div id="myModal" class="modal">
<!-- Modal content -->
<div class="modal-content" style="padding-top: 10px; padding-left: 10px; padding-right:30px; left: 50px; top: 70px; width: 70%; height: 50%; ">
<span class="close">×</span>
<p style="line-break:strict">#Html.DisplayFor(modelItem => item.ErrorList)</p>
</div>
</div>
itemCount++;
}
Create a class called "MyButton" or whatever you want too. Then capture the click with JQuery. Extract the script id from the data attribute and post it.
$(document).on('click', '.MyButton', function () {
var scriptid = $(this).data("scriptid");
$.ajax({
type: "POST",
url: "/Script/RunScript/",
data: {id:scriptid}
});
});
Hope that helps.
Your current code is generating a button with btnRun as Id, for each iteration of the loop. That means, If your Model is a collection of 10 items, your code will generate 10 buttons, all with the same Id value.
Element's Id' should be unique. The markup generated by your current code in invalid because it generates more than one element same Id attribute value.
The jquery selector expression $("#btnRun") will return you the first item matching the selector expression. In this case you will get the first item even though you are clicking the button in a different row.
You can remove the Id attribute on the button and wire up the click event with the a more generic jquery selector (ex : css class selector/name selector/ data attribute selector etc)
Here is an example, where i am adding an html5 data attribute to the button and storing the url with(route values) to the RunScript action method.
<td>
<button data-url="#Url.Action("RunScript", "Script",
new {scriptId = item.scriptId})"> Run Script</button>
</td>
And you will wire up the click event to input element's which has a data-url attribute
$(function () {
$("button[data-url]").click(function(e) {
e.preventDefault();
var url = $(this).data("url");
$.getJSON(url).done(function(data) {
console.log(data);
});
});
});
Since we used the Url.Action helper inside the razor view to generate the url, now your javascript code can be easily moved to an external js file as well.
My personal prefer
I have a structure like this:
<div> <a href='#'>Hyperlink</a> </div>
<div>
<table>
<tr>
<td>Row1</td>
<td><button>Click</button></td>
</tr>
<tr>
<td>Row2</td>
<td><button>Click</button></td>
</tr>
<tr>
<td>Row3</td>
<td><button>Click</button></td>
</tr>
</table>
</div>
I am not able to navigate to buttons using tab but on shift+tab they are getting focus and can be accessed. A lot of classes have been used with each HTML element but tabindex has not been used.
What can be the issue? Please help.
Have a look at the global tabindex attribute in HTML.
http://www.w3schools.com/tags/att_global_tabindex.asp
tabindex="n"
You can give elements the sequence they should be tabbed in, and that would most likely fix any tabbing focus issues you have right now.
You have to define tabindex for the elements and use a bit jQuery
$(function(){
$('#anchor').click(function(){
$(this).html('Pres Tab now');
});
});
.hidden{
position:absolute;
top:-100px;
}
input{
width:0px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
Click me
</div>
<div>
<table>
<tr>
<td>Row1</td><td><button tabindex="2">Click</button></td>
</tr>
<tr>
<td>Row2</td><td><button tabindex="3">Click</button></td>
</tr>
<tr>
<td>Row3</td><td><button tabindex="4">Click</button></td>
</tr>
</table>
<div class="hidden"><input type="text" tabindex="5" onfocus="$('#anchor').focus()" /></div>
</div>
You Need One Dummy Input For Rotating Tab Order It Is In Hidden Mode
$(function(){
$('#anchor').click(function(){
$(this).html('Check Tab now');
});
});
.hidden{
position:absolute;
top:-100px;
}
input{
width:0px;
}
a{
text-decoration:none;
color:#ff8800;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
Click me
</div>
<div>
<table>
<tr>
<td>Row1</td><td><button tabindex="2">Click</button></td>
</tr>
<tr>
<td>Row2</td><td><button tabindex="3">Click</button></td>
</tr>
<tr>
<td>Row3</td><td><button tabindex="4">Click</button></td>
</tr>
</table>
<div class="hidden"><input type="text" tabindex="5" onfocus="$('#anchor').focus()" /></div>
</div>
How to apply width to the table columns to avoid changing column width when no results found inside it. Columns in this table can also be hidden dynamically so I can't set fixed width on th element.
<table>
<thead>
<tr>
<th>col1</th>
<th>col2 <i>Filter:</i> <input type="text" ng-model="searchText"></th>
<th ng-hide="hideCol3">col3 <button ng-click="hideCol3 = !hideCol3">Hide column</button></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="d in data | filter: searchText">
<td>{{d.col1}}</td>
<td>{{d.col2}}</td>
<td ng-hide="hideCol3">{{d.col3}}</td>
</tr>
</tbody>
</table>
Columns might be hidden in the table. So for example if I go to the plunker example, hide col3, and search for none existing text, lets say 'abc' the width of the table columns width changes.
I would like table to adjust width when some column is hidden (it is doing it now), but when I'm filtering and there are no results I don't want column width to change
plunker
Here is a way to do it https://jsfiddle.net/kblau237/qkn1z0LL/2/
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>NNIndex</title>
<script src="~/Scripts/jquery-1.9.1.min.js"></script>
<script data-semver="1.2.13" src="http://code.angularjs.org/1.2.13/angular.js" data-require="angular.js#1.2.x"></script>
<script src="~/Scripts/app.js"></script>
<style>
th, td {
border: 1px solid black;
}
table {
width: 100%;
}
</style>
<script type="text/javascript">
$(function () {
//http://stackoverflow.com/questions/1636201/is-the-order-objects-are-return-by-a-jquery-selector-specified
var cols = $(".manageWidth"); //access each ids with [0]..[2] usejquery each
$.each(cols, function (index, value) {
$('<input>').attr({
type: 'hidden',
class: 'hdnDyn',
id: "hdnDyn" + index,
value: window.getComputedStyle(cols[index], null).getPropertyValue("width")
}).appendTo('body');
});
$("input").keyup(function () {
KeepWidthSame();
});
$(".col3").click(function () {
KeepWidthSame();
});
function KeepWidthSame() {
$("table").css("width", "auto");
var cols = $(".manageWidth");
$.each(cols, function (index, value) {
$(this).css("width", $(".hdnDyn")[index].value);
});
}
})
</script>
</head>
<body ng-app="plunker" ng-controller="MainCtrl">
<table>
<thead>
<tr>
<th class="manageWidth">col1</th>
<th class="manageWidth">col2 <i>Filter:</i> <input type="text" ng-model="searchText"></th>
<th class="manageWidth col3" ng-hide="hideCol3">col3 <button ng-click="hideCol3 = !hideCol3">Hide column</button></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="d in data | filter: searchText">
<td>{{d.col1}}</td>
<td>{{d.col2}}</td>
<td ng-hide="hideCol3">{{d.col3}}</td>
</tr>
</tbody>
</table>
</body>
</html>