I have a table I've built in an app that when I click delete removes all rows following the row that was deleted on submit. That means that the table looks good to the user with just that one row removed, but when it hits the viewmodel on post action, those subsequent rows aren't included.
I've added some pretty complex code that goes all over the place to edit the index values of the rows but that ended up confusing the problem even more with some values replacing others and some other values just being set to 0. I know there has to be a more simple way.
I set this example back to the more simplified version where the delete appears to work well but then doesn't include any subsequent values in the viewModel when it hits the controller.
Here is the HTML Table
<input type="button" value="Add" class="button is-primary" id="btnAdd" />
<table id="tblPart" style="table-layout:fixed; width:100%;">
<thead>
<tr>
<th>
Part Number
</th>
<th>
Quantity
</th>
<th></th>
</tr>
</thead>
<tbody>
#for (var i = 0; i < Model.NumberModel.Count(); i++)
{
<tr >
<td >
#Html.TextBoxFor(modelItem => Model.NumberModel[i].PartNum, new { id = $"part{i}", required = "required", #class = "partTest" })
</td>
<td>
#Html.TextBoxFor(modelItem => Model.NumberModel[i].Quantity, new { type = "number", min = "0", id = $"quantity{i}", required = "required" })
</td>
<td>
<input type='button'
onclick='Remove(this)'
value='Remove' />
</td>
</tr>
}
</tbody>
</table>
Here is the JS
<script>
function Remove(button) {
//Determine the reference of the Row using the Button.
var row = $(button).closest("TR");
var name = $("TD", row).eq(0).html();
//console.log(row + name);
var index = 0;
var table = $("#tblPart")[0];
//Delete the Table row using it's Index.
table.deleteRow(row[0].rowIndex);
}
</script>
Thank you for your assistance.
When you delete the row, all subsequent rows index is wrong, you need to re-index the remaining rows on delete. If you for instance delete row with index 3 and then you have rows 0-2 and rows 4-6, 4-6 will be left out since there is no index 3, to fix this, you need to reindex the id and name attributes on the form fields after delete, also, you should consider using const and let in your function as var should be used for global variables, lastly, I added jquery tag to your post as you are mixing javascript and jquery in your code:
function Remove(button) {
//Determine the reference of the Row using the Button.
const row = $(button).closest("TR");
const name = $("TD", row).eq(0).html(); //this seems unnecessary
let index = 0; //this seems unnecessary
const table = $("#tblPart")[0];
//Delete the Table row using it's Index.
table.deleteRow(row[0].rowIndex);
//re-index
$('#tblPart tbody tr').each(function(i, el) {
//get the form fields
const $partnuminput = $(el).find('input[name*="PartNum"]');
const $quantityinput = $(el).find('input[name*="Quantity"]');
//use the iterator parameter of .each to set the index correctly
$partnuminput.attr("name", $partnuminput.attr("name).replace(/\d+/g, i);
$partnuminput.attr("id", $partnuminput.attr("id").replace(/\d+/g, i);
$quantityinput.attr("name", $partnuminput.attr("name).replace(/\d+/g, i);
$quantityinput.attr("id", $partnuminput.attr("id").replace(/\d+/g, i);
});
}
Related
So I problem is that I want to generate a random ID for each in each row and then change the inner HTML of the specified whenever a certain button is clicked.
I have tried adding the onload attribute for each row that is created to try to get the id with a function and then pass the id when the function is called but it didn't work
function add(){
let taskInfo = `
<tr>
<td>${generateId(4)}</td>
<td>${productID}</td>
<td>-</td>
<td class="taskid"id="${generateId(4)}">Idle</td>
<td>
<span class="action-start" id="${generateId(4)}"onclick="start(getId())">Start</span>
<span class="action-stop" >Stop</span>
</td>
</tr>
`
let newTask = tbody.insertRow(tbody.rows.length);
newTask.innerHTML = taskInfo;
console.log("New task added!")
}
This is the function that adds the rows to the table ^
So what I am expecting to get is that when the users click start the status changes to a certain status, individually in each row
Iam completely confused at a point and need anyone's help here. Went through various examples but nothing could help.
I have a created dynamic table, added with checkboxes. Now whenever a row is selected its id will be bound to an array and it will be diplayed at the top of table.
What I need is:The code for functionality of select all check box. And whenever all the rows are selected by select all checkbox, its ids has to be displayed.
Below is the code for the table:
<table>
<thead>
<tr>
<th>
<input name="all"
type="checkbox"
ng-click="selectAll()" />
</th>
<th>ID</th>
<th>Date</th>
</tr>
</thead>
<tbody ng-repeat="x in cons">
<tr>
<td>
<input type="checkbox"
name="selectedids[]"
value="{{x.id}}"
ng-checked="idSelection.indexOf(x.id) > -1"
ng-click="toggleSelection(x.id, idSelection)"> </td>
<td>{{x.id}}</td>
<td>{{x.title}}</td>
</tr>
</tbody>
app.js:
$scope.idSelection = [];
$scope.toggleSelection = function toggleSelection(selectionName, listSelection) {
var idx = listSelection.indexOf(selectionName);
// is currently selected
if (idx > -1) {
listSelection.splice(idx, 1);
}
// is newly selected
else {
listSelection.push(selectionName);
}
};
//$scope.selectAll=function(){}
//Need code for this function to work
Here is a demo: http://plnkr.co/edit/m9eQeXRMwzRdfCUi5YpX?p=preview.
Will be grateful, if anyone can guide.
You need a variable to keep track of whether 'All' is currently active or not. If not, we create a new array of all item id's using the array map function, and pass this to idSelection. If allSelected is currently active, we pass an empty array to idSelection
$scope.allSelected = false;
$scope.selectAll = function() {
$scope.allSelected = !$scope.allSelected;
if($scope.allSelected) {
$scope.idSelection = $scope.cons.map(function(item) {
return item.id;
});
} else {
$scope.idSelection = [];
}
}
I have a bit of HTML here:
<tr taskId="(#=obj.task.id#)" assigId="(#=obj.assig.id#)" class="assigEditRow" >
<td><select name="resourceId" class="get-resources formElements"></select></td>
<td><span class="resources-units"></span></td>
<td><span class="resources-quantity"></span></td>
<td><input type="text" placeholder="Required Q"></td>
<td align="center"><span class="teamworkIcon delAssig" style="cursor: pointer">d</span></td>
</tr>
And a bit of JS here:
'use strict';
function addResourceFunction(){
let ResourcesJSON = (json) => {
let Resources = json;
console.log(Resources);
let contactsLength = json.length;
let arrayCounter = -1;
let resID;
let resName;
let resUnit;
let resQuantity;
let Option = $('<option />');
let assignedID = $('tr.assigEditRow:last').attr("assigId");
while(arrayCounter <= contactsLength) {
arrayCounter++;
resID = Resources[arrayCounter].ID;
resName = Resources[arrayCounter].name;
resUnit = Resources[arrayCounter].unit;
resQuantity = Resources[arrayCounter].quantity;
$('.assigEditRow').last().find('select').append($('<option>', {
value: resName.toString(),
text: resName.toString(),
resourceID: resID.toString(),
resourceUnit: resUnit.toString(),
resourceQuantity: resQuantity.toString()
}));
}
}
$.getJSON("MY JSON URL IS HERE", function(json) {
ResourcesJSON(json);
});
};
So what's actually going on here: I get my data from the URL (JSON array), trigger the addResourceFunction() on click to create a new table row and to add a new select with options passed from the array. As you see from my HTML markup, the select input is placed in td.get-resources, and all that works good. I get my date set, I populate the select field and all works good. I can add as many rows/select dropdowns as I want.
Also, every option has a few custom attributes (you can see it in my JS code above), and I want to add the values of those attributes to the second and third column of the row (in HTML those are span.resources-units and span.resources-quantity). The thing is, I have no clue how to make it work 1:1, meaning that one select dropdown "alters" only units and quantity of its own row. Below is the code for that:
let idCounter = 1;
$(document).on('change', '.get-resources', function() {
$('.assigEditRow').last().find('.resources-units').attr('id', 'units-' + idCounter);
$('.assigEditRow').last().find('.resources-quantity').attr('id', 'quantity-' + idCounter);
this.resourceUn = $( ".get-resources option:selected" ).attr( "resourceUnit" );
this.resourceQuant = $( ".get-resources option:selected" ).attr( "resourceQuantity" );
$('#units-' + idCounter).append(this.resourceUn);
$('#quantity-' + idCounter).append(this.resourceQuant);
idCounter++;
});
What happens is that if I add one select input, and change options, the thing works. When I add another one and change its options, it gets attributes of the first one. Adding more - same thing. Whatever I change, it takes the attribute value of the first item added.
Try getting the id from the element instead of from the variable, since you always update the element with the id of the counter, instead of the element with the id of the row that was clicked.
Hmm, what does the counter do exactly? The more I look at it, the less I understand. What I do know is that you're not selecting the correct elements by using the idCounter to reference the correct row.
You want to do something like
$(document).on('change', '.get-resources', function() {
//var row = this;
this.find(/* Some path to the second column */).att(/* some att to change */);
this.find(/* Some path to the third column */).att(/* some att to change */);
});
where you always use the row as the root again, instead of finding a certain id, so you only update that row.
Native:
<table>
<tr>
<td>
<select>
<option data-text="resName1" data-resourceID="resID1" data-resourceUnit="resUnit1" data-resourceQuantity="resQuantity1">1</option>
<option data-text="resName2" data-resourceID="resID2" data-resourceUnit="resUnit2" data-resourceQuantity="resQuantity2">2</option>
<option data-text="resName3" data-resourceID="resID3" data-resourceUnit="resUnit3" data-resourceQuantity="resQuantity3">3</option>
</select>
</td>
<td>
<div class="column2"></div>
</td>
<td>
<div class="column3"></div>
</td>
</tr>
</table>
<script>
document.addEventListener('change', function ( event ) {
var select = event.target,
option = select.options[select.selectedIndex],
values = {
'text' : option.getAttribute('data-text'),
'resourceID' : option.getAttribute('data-resourceID'),
'resourceUnit' : option.getAttribute('data-resourceUnit'),
'resourceQuantity' : option.getAttribute('data-resourceQuantity')
},
row = select.parentNode.parentNode,/* depending on how deep the select is nested into the tr element */
column2 = row.querySelector('.column2'),
column3 = row.querySelector('.column3');
column2.textContent = 'some string with the values you want';
column3.textContent = 'some string with the other values you want';
});
</script>
Basically you start with the select that was changed, from there you get the option node that was clicked. Then you get the attributes you need from that option. Then you go up a few nodes to the row parent and find the two columns inside that row. Then you can set the content of these two columns.
Here is my code:
<body>
<div id="metric_results">
<div id="form">
<form name="myForm" >
...//get course IDnumber and course score
</form>
</div>
<div id="table">
<table id="TABLE" border = '1'>
</table>
</div>
<script type="text/javascript">
//when click on "add" button,call "addTable" function.
document.getElementById("add_button").onclick = function() {addTable()};
document.getElementById("delete_button").onclick = function() {DeleteTableRow()};
var stock = new Array();
var i = 0;
function addTable() { //create table with 3 column(idnumber,score,checkbox)
var c = document.createElement("INPUT");
c.setAttribute("type", "checkbox");
stock[i] = new Array(id, score);//id= course ID number,score=course score, get from form
//Create table row and append it to end of table
var tr = document.createElement('TR');
for (j = 0; j < 3; j++) {
var td = document.createElement('TD');
if(j == 2){
td.setAttribute("id","check_box"+(i+1));
td.appendChild(c);}
else{
td.appendChild(document.createTextNode(stock[i][j]));}
tr.appendChild(td);
}
table.appendChild(tr);
i=i+1
}
// Delete courses that their checkbox is on.
function DeleteTableRow(){
var check_boxes=new Array();
for(j=0; j<i ;j++){
check_boxes[j]= document.getElementById("check_box"+(j+1));
if(check_boxes[j].checked==true){document.getElementById("TABLE").deleteRow(j+1);}
}
</script>
</body>
I create a form which get course idnumber and course score.At first, when I fill the form, javascript creates a table so when I click the "add" button, I can add courses. Now, I want to add another function named DeleteTableRow() to delete the selected rows.
When I create the table for each course,I create a checkbox column and set "id" for each rows checkbox(td.setAttribute("id","check_box"+(i+1));) so in the DeleteTableRow() function I use getElementById("check_box"+(j+1)) in the for loop.
Everything is OK but I can't check the value of the check box and I can't delete the selected rows. what should I do and how do I check it?
Your main problem is that in your addTable function you set the id attribute on the table cell, rather than the checkbox. Naturally, cells don't have a checked attribute. You could fix this by doing the setAttribute('id', ...) on c, before the loop.
Note there are a few strange things about your code - for example, you should really use the literal [] when defining a new array, rather than the new Array() call; but having said that there doesn't seem to be any need for the check_boxes array in the first place, since you never use it.
In any case, your code would be a lot simpler if you used something like jQuery, which is pretty much the default for doing DOM manipulation in Javascript these days.
My application allows you to track orders in a store database. This database contains a weak entity used for notes which is attached to an orderID. I want to allow users to be able to apply to same 'note' to many orders at the same time, but there are some fields in the notes table that are dependent on the location of the sale. In other words, you should only be allowed to apply the same note if all the sale locations are the same.
Simplified View:
#using (Html.BeginForm("Create", "Note", FormMethod.Get, new { name = "editForm" }))
{
<table id="DataTable">
<tr>
<th>
<input type="button" value="Edit" onclick="checkboxValidation()"/>
</th>
<th>
#Html.DisplayNameFor(model => model.OrderID)
</th>
<th>
#Html.DisplayNameFor(model => model.location)
</th>
</tr>
#foreach (var item in Model)
{
<tr >
<td>
<input type="checkbox" name="ids" value="#item.orderID" />
</td>
<td>
#Html.ActionLink(item.OrderID.ToString(), "Details", "Search", new { orderID = item.orderID.ToString() }, null)
</td>
<td>
#Html.DisplayFor(modelItem => item.location)
</td>
</tr>
}
</table>
checkboxValidation() is a javascript function I wrote to check if at least 1 checkbox is checked. How would I add a check to make sure all of the locations on checked lines are the same? Is this even possible? Thanks
EDIT: I missed a detail. When clicking the edit button, if the check is successful, it submits the form, which brings up the notes editor.
Should be fairly straightforward using JQuery:
// find all the checked rows
var checkedItems = $("#DataTable").find("tr td input[type=checkbox]");
// construct a locations array for all checked items
var locations = [];
checkedItems.each(function(index, element) {
if ($(element).is(":checked")) {
locations.push($(this).closest("td").next("td").next("td").text().trim());
}
});
// confirm each location is the same
var valid = true;
locations.each(function(index, element) {
if (index > 0 && locations[index-1] != element) {
valid = false;
return;
}
});
One additional thing you might want to do, is add some data tags to your tr and td elements, so that you can write more robust selectors that won't break with a minor UI re-arrangement (like tr[data-role=check] and tr[data-role=location], etc).
(Using JQuery closest and and JQuery each.)