checking a single checkbox per html row using angular js - html

i have a table that loads multiple checkboxes and selectboxes.when i click on one checkbox or select box it automatically selects every other box on the table .i want to have the option to choose either one checkbox or select box per row on it own.
<tr id="TableBody" ng-repeat="code in Register.RegisterDetails">
<td>{{$index+1}}</td>
<td ng-bind="code .CodeID"><input type="text" ng-model="Register.CodeID" /></td>
<td ng-bind="code .name"><input type="text" ng-model="Register.Firstname" /></td>
<td ng-bind="code .Lastname"><input type="text" ng-model="Register.Lastname" /></td>
<td><input type="checkbox" ng-model="Register.Presentstatus" id="PresentCheckbox" name="PresentCheckbox" /></td>
<td><select id="reasons" name="reasons" ng-model="Register.Category" ng-disabled="Register.Presentstatus" ng-clicked="Register.Presentstatus && O" ></td>
</tr>
my module that gets my data
function Register(){ self.RegisterDetails = function () {
var params = { pass params here };
return $http.get
{
url: GetRegisterDetails,
params: params,
success: function (data) {
self.RegisterDetails = data.data;
}
});
}
my controller
ngAppModule.controller('RegisterController',['$scope','$http',function($scope,$http)
{
var self = this;
$scope.Register = new Register($http);
}]);
all the above code works fine. i just dont know how to check a single box per row.sorry im new to this site

The main problem you're running into is you are binding to the wrong this inside your ng-repeat.
Your HTML currently repeats a checkbox for every code, but binds that to the same object property Register.Presentstatus.
<tr id="TableBody" ng-repeat="code in Register.RegisterDetails">
<td>{{$index+1}}</td>
....
<td><input type="checkbox" ng-model="Register.Presentstatus" .../></td>
</tr>
You'll need to bind this to a row-specific (code-specific) property if you want each row to have independent check boxes. Perhaps you are looking for something that binds the checkbox to an element in an array:
<tr id="TableBody" ng-repeat="code in Register.RegisterDetails">
<td>{{$index+1}}</td>
....
<td><input type="checkbox" ng-model="Register.Presentstatus[$index]" .../></td>
</tr>
or actually binds to a property of the code object
<tr id="TableBody" ng-repeat="code in Register.RegisterDetails">
<td>{{$index+1}}</td>
....
<td><input type="checkbox" ng-model="code.Presentstatus" .../></td>
</tr>

Since youur ng-model="Register.Presentstatus" is repeating and is same for all so you have same binding for all rows. you can alter them to have different binding

Related

Posting row model data from a table within a form (no JS)

I ran into an almost identical issue before and posted a question about it here: Posting data of a single table row when table is in one form We were able to solve it but it felt pretty hacky. To summarize that post, I was attempting to use AJAX and JS to POST values from a table row to a controller. The problem was that every row would be serialized within the form. To solve this, I serialized only the row I needed.
This time I am running into the same issue, the only difference being that I'm not using AJAX and am submitting the model data from the table row directly to the controller action.
I tried to use both the foreach and for loops to generate table rows.
The foreach loop always POSTs the first row in the table, even if I click submit button on the second row.
The for loop doesn't POST anything, or at least I get all null values in my controller action's "shipment" parameter.
I also tried to encase the row in a form, but HTML does not allow to have a <form> in <tbody>.
What I want is to be be able to POST a single row (generated by looping through a list for models) directly to the "UpdateShipment" controller action. All of this without using AJAX.
HTML code:
#model OrderTrackingContract.SalesOrder
#foreach (var lineItem in Model.LineItems)
{
<table class="lineItemTables">
//line items table
</table>
#if (lineItem.Shipments.Count > 0)
{
<form method="post">
<table class="table shipmentTable">
<thead>
<tr>
<th>
ShipmentID
</th>
<th>
Qty Shipped
</th>
<th>
Actions
</th>
</tr>
</thead>
<tbody>
#for (int i = 0; i < lineItem.Shipments.Count; i++)
{
<tr>
<td>
<input class="shipmentID" asp-for="#lineItem.Shipments[i].ShipmentID" />
</td>
<td>
<input class="qtyShipped" asp-for="#lineItem.Shipments[i].QtyShipped" value="#lineItem.Shipments[i].QtyShipped" min="1" max="999" />
</td>
<td>
<input class="updateButton" type="submit" value="Update" asp-action="UpdateShipment" asp-controller="Shipments" />
<input class="deleteButton" type="submit" value="Delete" asp-route-shipmentID="#lineItem.Shipments[i].ShipmentID" asp-action="DeleteShipment" asp-controller="Shipments" />
</td>
</tr>
}
</tbody>
</table>
</form>
}
}
Controller action:
[HttpPost]
public IActionResult UpdateShipment(Shipment shipment)
{
_orderTrackingService.UpdateShipmentByID(shipment.ShipmentID, shipment.QtyShipped);
return NoContent();
}
EDIT: I used fiddler and I'm starting to understand what's going on. Both for and foreach loop submit the whole form because the whole table is in it.
Using a for loop I am forced to write asp-for="#lineItem.Shipments[i].ShipmentID", which means the controller must accept a parameter of LineItem lineItem.
Using foreach loop I am able to write asp-for="#shipment.ShipmentID, but because the generated attributes of the <input> are identical, the 'Shipment shipment' parameter binds to the first values POSTed.
What I want is to be be able to POST a single row (generated by looping through a list for models) directly to the "UpdateShipment" controller action. All of this without using AJAX.
To achieve above requirement, you can try to generate <form> and <table> for each Shipment item, like below.
#foreach (var lineItem in Model.LineItems)
{
<table class="table shipmentTable">
<thead>
<tr>
<th>
ShipmentID
</th>
<th>
Qty Shipped
</th>
<th>
Actions
</th>
</tr>
</thead>
</table>
#if (lineItem.Shipments.Count > 0)
{
foreach (var Shipment in lineItem.Shipments)
{
<form method="post">
<table class="table shipmentTable">
<tbody>
<tr>
<td>
<input class="shipmentID" asp-for="#Shipment.ShipmentID" />
</td>
<td>
<input class="qtyShipped" asp-for="#Shipment.QtyShipped" value="#Shipment.QtyShipped" min="1" max="999" />
</td>
<td>
<input class="updateButton" type="submit" value="Update" asp-action="UpdateShipment" asp-controller="Shipments" />
<input class="deleteButton" type="submit" value="Delete" asp-route-shipmentID="#Shipment.ShipmentID" asp-action="DeleteShipment" asp-controller="Shipments" />
</td>
</tr>
</tbody>
</table>
</form>
}
}
}
Test Result

Posting data of a single table row when table is in one form

I have one form that has a whole table inside it. A for loop iterates through a list of items and adds records to the table. Each record has a submit button. When I click that button, I use AJAX to serialize
and POST the form (because I need to reload a partial), and expect to POST data about that single item in the record to the controller.
In other words, if a table is displaying records from a looped list, I want to be able to POST a single list item to the controller.
What is holding me back is the for and foreach loops when I try to POST a record:
If I use a foreach loop the form always POSTs the very first record in the table, even if I click the button on other records.
If I use a for loop I am required to POST the whole list to my controller because the list is a parameter inside another object. This means I am forced to bind to the model that contains the list.
Possible reason for the issue: I suspect this has something to do with the values of the name attributes in the HTML that asp-for attribute generates. With a for loop the names are not unique, so the binding process assumes the first record with the correct names. With a foreach loop, the names are unique, but the binding process needs to bind to the model that contains the list.
HTML View (simplified). A foreach loop in place of the for loop would look like #foreach (var shipment in lineItem.Shipments) { <tr>... </tr> }
#model OrderTrackingContract.SalesOrder
#foreach (var lineItem in Model.LineItems)
{
<table class="lineItemTables">
//line items table
</table>
#if (lineItem.Shipments.Count > 0)
{
<form method="post">
<table class="table shipmentTable">
<thead>
<tr>
<th>
ShipmentID
</th>
<th>
Qty Shipped
</th>
<th>
Actions
</th>
</tr>
</thead>
<tbody>
#for (int i = 0; i < lineItem.Shipments.Count; i++)
{
<tr>
<td>
<input id="shipmentID" asp-for="#lineItem.Shipments[i].ShipmentID" />
</td>
<td>
<input id="qtyShipped" asp-for="#lineItem.Shipments[i].QtyShipped" value="#lineItem.Shipments[i].QtyShipped" min="1" max="999" />
</td>
<td>
<input class="updateButton" type="submit" value="Update" />
</td>
</tr>
}
</tbody>
</table>
</form>
}
}
AJAX
$('.updateButton').on('click', function () {
var form = $(this).closest('form');
form.submit(function (event) {
event.preventDefault(); /* stop form from submitting normally */
$.ajax({
url: "/OrderTracking/UpdateShipment",
type: "POST",
data: form.serialize(),
success: function () {
//some code here
}
});
});
});
Controller Action
[HttpPost]
public IActionResult UpdateShipment(Shipment shipment)
{
_orderTrackingService.UpdateShipmentByID(shipment.ShipmentID, shipment.QtyShipped);
return NoContent();
}
I have tried to extract the values from the tags using the tag ids shipmentID and qtyShipped closest to the button and pass them to the controller, which worked. However, I want to avoid doing that and instead actually POST the form.
If you just want to pass data for a single row then just get the data for that row and pass to your action... don't serialize every row and post it.
You should do 2 things...
First update the inputs in your loop by giving them a class and not an id. id's should be unique for the page, but you are creating the same id="shipmentID" and id="qtyShipped" for your inputs. Don't do this, the asp-for will create your id and name attributes for you.
<tbody>
#for (int i = 0; i < lineItem.Shipments.Count; i++)
{
<tr>
<td>
<input class="shipmentID" asp-for="#lineItem.Shipments[i].ShipmentID" />
</td>
<td>
<input class="qtyShipped" asp-for="#lineItem.Shipments[i].QtyShipped" value="#lineItem.Shipments[i].QtyShipped" min="1" max="999" />
</td>
<td>
<input class="updateButton" type="submit" value="Update" />
</td>
</tr>
}
</tbody>
Next, update your ajax request to find the row the button is in then get the values of the inputs of that row and make a data object to be passed to your action. Like this:
$('.updateButton').on('click', function (e) {
e.preventDefault(); /* stop form from submitting normally */
var row = $(this).closest('tr'),
shipmentID = $('.shipmentID', row),
qtyShipped = $('.qtyShipped', row);
var data = { ShipmentID: shipmentID.val(), QtyShipped: qtyShipped.val() };
$.ajax({
url: "/OrderTracking/UpdateShipment",
type: "POST",
data: data,
success: function () {
//some code here
}
});
});
You were also attaching a submit event to your form everytime a submit button was clicked. This is bad and would result in 3 submit events being attached if 3 buttons were clicked, so I removed this.

How to clear angular smart filter upon clicking reset button

Here I am developing simple angular html form, I am using angular smart table. How can i clear smart table search filter after i click reset button
My html
<tr>
<th></th>
<th><input st-search="studentId" st-delay="1200" /></th>
<th><input st-search="studentName" st-delay="1200" /></th>
<th><filter-options code-id="200" search-field="studentType">
</filter-options></th>
</tr>
<button id="cm-ResetBtn" name="cm-ResetBtn" type="button" ng-click="Reset()">Reset</button>
My angular code
$scope.Reset = function () {
//TODO
}
I guess
JS
$scope.Reset = function () {
$scope.studentId = '';
$scope.studentName = '';
}
HTML
Need to add ng-model attribute to inputs
<th><input ng-model="studentId" st-search="studentId" st-delay="1200" /></th>
<th><input ng-model="studentName" st-search="studentName" st-delay="1200" /></th>
JSFiddle example
Also you can check this question Smart Table not update when search filter value changes from javascript
I fixed by $state.reload(). That works as expected
You can examine Atkinson's post and it worked for me!
How to trigger ngClick programmatically

Dynamically add property to object in angularjs ng-repeat

I have a list of object and iterating that list using ng-repeat to generate table row. each td contains source name and checkbox. I want to bind the checkbox with a property which is not available into list. how that is possible? The list is like that:-
scope.reasons = [
{sourceName:'Lack of rainfall'},
{ sourceName: 'Change in land use' },
{sourceName:'Change in Land Cover'}
];
and the HTML code is like that:-
<table>
<tr ng-repeat="source in reasons">
<td>{{source.sourceName}}</td>
<td><input type="checkbox" ng-checked="source.postAdequate"></td>
</tr>
</table>
You can do this using the ng-model attribute, ng-change is just for the checking purposes that is change detection.
<table>
<tr ng-repeat="source in reasons">
<td>{{source.sourceName}}</td>
<td>
<input type="checkbox" ng-model="source.postAdequate" ng-change="changeDet()">
</td>
</tr>
</table>
Demo Fiddle
Hope this helps
Try this:
<input type="checkbox" ng-model="source.postAdequate">
See here jsfiddle link:
https://jsfiddle.net/avnesh2/5cpm48tc/2/
But it will add source.postAdequate: true/false only if you click, remains objects will remains same.
So if you want to add source.postAdequate: true/false in all add in $scope.reasons before only.
Hope this will help you.
Using ng-model instead of ng-checked will add property internally when checkbox is changed
<input type="checkbox" ng-model="source.postAdequate"></td>
If you must have that property on all objects iterate the array and add it
scope.reasons.forEach(function(item){
item.postAdequate = false
})
Can you loop the scope object once to initially set postAdequate:false for all items. Then bind that object in checkbox ng-model.
angular.forEach($scope.reasons, function(e,i){
e.postAdequate = false;
});
html code
<table>
<tr ng-repeat="source in reasons">
<td>{{source.sourceName}}</td>
<td>
<input type="checkbox" ng-model="source.postAdequate" ng-click="clickfunction(source.postAdequate)">
</td></tr>
</table>

Angular JS- Calculate the sum of repeated elements using ng-repeat

I am newbie to Angular js. I am trying to calculate the sum of values of third column and save result into downtime box.
Here, I had already done.
1.Dynamically Add/remove the row.
2.Calculate the difference between the 1st column and 2nd column and save the result into third column.
3.Now,sum the values of third column and save into textbox.
Now, third point is not working.
HTML:
<!doctype html>
<html ng-app="Myapp">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
</head>
<body ng-controller="myctrl">
<table id="t1" style="border:none;">
<tr><th>Start</th><th>Stop</th><th>Downtime(In Min)</th><th>Reason</th></tr>
<tr ng-repeat="item in invoice">
<td><input type="text" required ng-model="$invoice.start" name="r1[]"></td>
<td><input type="text" required ng-model="$invoice.stop" ng-blur="diff($invoice)" name="r2[]"></td>
<td><input type="text" name="r3[]" ng-model="$invoice.diff"/></td>
<td><input type="text" ng-model="$invoice.reason" name="r4[]" ></td>
<td style="border:none;"><a href ng-click="remove(item)">X</a></td>
</tr>
<tr style="border:none;">
<td style="border:none;"><a href ng-click="add()">+</a></td>
</tr>
</table>
<br/>
<div>
<span class="labelCode">Total Downtime</span><input required type="text" ng-value="run()" name="Tot_D" /></span></br>
</div>
Angular js
var myapp=angular.module("Myapp",[]);
myapp.controller("myctrl",function($scope){
$scope.invoice = [{
start :"7:00",
stop:"7:30" ,
reason: "M/C Ready to Start",
}]
$scope.add= function(){
$scope.invoice.push({
start:"7:30",
stop:"8:00"
});
};
//Remove the rows
$scope.remove=function(index){
$scope.invoice.splice(index,1);
};
$scope.diff = function(item) {
item.diff = computeDiff(item.start,item.stop);
}
function computeDiff(start, stop) {
if (start && stop) {
var s_hr = start.split(":")[0];
var s_min = start.split(":")[1];
var e_hr = stop.split(":")[0];
var e_min = stop.split(":")[1];
return Math.abs((parseInt(e_hr) - parseInt(s_hr)) * 60) + Math.abs(parseInt(e_min) - parseInt(s_min))
}
}
$scope.run = function(){
var total = 0;
for(var i = 0; i < $scope.invoice.length; i++){
var product = $scope.invoice[i];
total += parseInt($scope.diff());
}
return total;
}
});
Sum of repeated values of third column is not updating into downtime text box.
I dont where I am going wrong.Please help me out.Thanks in advance.
First of all I suggest you to us ng-init directive for every iteration to calculate, but it's Very Important to use functions inside ng-init. Something like this:
<tr ng-repeat="item in invoice">
<td><input type="text" ... ng-init="sum(item)"></td>
</tr>
Then inside your controller you can define that function and do there whatever you want, because ng-repeat will call that function for every iteration