I have a table sorted by properties "age" and "name" but I have a counter of rows (counterR) that shows the numbers of rows in the table.
I want to exclude this item on OrderBy because is ordered too, I need it would be static and always ordered but I canĀ“t.
There's the Plunker link of my problem: http://plnkr.co/edit/MJYayUANphxksbGkyEcj?p=preview
HTML:
<body ng-controller="MainCtrl">
<table border="0">
<thead>
<tr>
<th>#</th>
<th>ID</th>
<th ng-click="sortType = 'name';sortReverse=!sortReverse">NAME</th>
<th ng-click="sortType = 'age';sortReverse=!sortReverse">AGE</th>
</tr>
</thead>
<tbody>
<tr ng-init="counterR=incrementCounter()" ng-repeat="item in items | orderBy:sortType:sortReverse">
<td>{{counterR}}</td>
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.age}}</td>
</tr>
</tbody>
</table>
JS:
$scope.items = [
{"name":"Jhon","id":"BB1","age":23},
{"name":"Austin","id":"BB2","age":44},
{"name":"Mark","id":"BB3","age":56},
{"name":"Jenn","id":"BB4","age":15}
];
var counterRow = 0;
$scope.incrementCounter = function(){
counterRow = counterRow + 1;
return counterRow;
}
Instead of storing the row number with the data - which doesn't work because the row numbers are not specific to a data row, but rather to a display position - you need to calculate the value "on the fly". In the scope of an ng-repeat you can do this with the special $index variable. That is, instead of
<td>{{counterR}}</td>
which reads a value from the data row, you would use
<td>{{$index+1}}</td>
(assuming sequential numbers starting from 1)
Related
I am having a table with two nested iterations, the first three columns where an array of object (item) iterates, and a fourth column is where an array of numbers should iterate ( total=[30,70,100] )
<table class="table">
<thead class="thead-dark">
<tr>
<th>Item</th>
<th>Unit Price</th>
<th>Quantity</th>
<th>Amount</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let i of item">
<td>{{i.product}}</td>
<td>{{i.price}}</td>
<td>{{i.quantity}}</td>
<ng-container *ngFor="let t of total">
<td>{{t}}</td>
</ng-container>
</tr>
</tbody>
</table>
The object array iterates fine, however, the problem is with the array of numbers ( total=[30,70,100] ), I tried to place the (ng-container *ngFor="let t of total") on different levels, but it always getting populated in a wrong way, I would appreciate advising me how to solve it.
Assuming your index level for the arrays are same, you can always use the index to track and repeat the element.
<tr *ngFor="let i of item; let in=index">
<td>{{i.product}}</td>
<td>{{i.price}}</td>
<td>{{i.quantity}}</td>
<ng-container *ngFor="let t of total[in]">
<td>{{t}}</td>
</ng-container>
</tr>
Edit: If the OP is multiplying quantity with price to come up with total then we don't need to maintain a separate array for that, we can just multiply it in the view and get it:
<tr *ngFor="let i of item; let in=index">
<td>{{i.product}}</td>
<td>{{i.price}}</td>
<td>{{i.quantity}}</td>
<td>{{i.price * i.quantity}}</td>
</tr>
We may need more information on how the data should be populated, what I can see is that the td tag is repeating in a wrong way when iterates with the total, having more tds than th tags. Also the total variable is a property inside the item or is separated?. For now I can give you examples for some scenarios:
If you want to have the total in a single td and the total is a property of i
<tr *ngFor="let i of item">
<td>{{i.product}}</td>
<td>{{i.price}}</td>
<td>{{i.quantity}}</td>
<td>{{i.total.join(,)}}</td>
</tr>
If you want to have the total in a single td and the total is just a variable outside the item array.
<tr *ngFor="let i of item let index = index">
<td>{{i.product}}</td>
<td>{{i.price}}</td>
<td>{{i.quantity}}</td>
<td>{{total[index]}}</td>
</tr>
If you want to have sum the total in a single td and the total is a property of i
<tr *ngFor="let i of item">
<td>{{i.product}}</td>
<td>{{i.price}}</td>
<td>{{i.quantity}}</td>
<td>{{i.total.reduce((a, b) => a + b, 0)}}</td>
</tr>
If you want to have sum the total in a single td and the total is just a variable outside the item array.
<tr *ngFor="let i of item let index = index">
<td>{{i.product}}</td>
<td>{{i.price}}</td>
<td>{{i.quantity}}</td>
<td>{{total[index].reduce((a, b) => a + b, 0)}}</td>
</tr>
I want to create 3 rows based on the columnList which contains 3 types of values i.e caption, shortCaption and columnName.
[{
caption : "First Name",
shortCaption: "FN",
columnName : "FIRST_NAME"
},{
caption : "Last Name",
shortCaption: "LN",
columnName : "LAST_NAME"
}
]
Currently i am generating table cell by iterating columnList with ng-repeat inside each row, here i am using ng-repeat three times which can be cause slowness, Is it possible to use ng-repeat only once at a time and generate all three rows, i also tried to use ng-repeat-start and ng-repeat-end but failed to get the output.
<tr>
<th ng-repeat="column in columnList">
{{column.caption}}
</th>
</tr>
<tr>
<th ng-repeat="column in columnList">
{{column.shortCaption}}
</th>
</tr>
<tr>
<th ng-repeat="column in columnList">
{{column.columnName}}
</th>
</tr>
http://plnkr.co/n0XKuwxOY8e1zjLfYwFI
template.html
<tr ng-repeat="column in columnList">
<td ng-repeat="key in getKeys()" ng-bind="::column[key]"></td>
</tr>
Controller.js
$scope.getKeys = function() {
return ['caption', 'shortCaption', 'columnName'];
}
This uses the ng-repeat twice. If you are sure about the keys of the objects in your column list, you can eliminate the 2nd ng-repeat - but the performance improvement will be negligible unless you have more than 500+ rows.
I'm trying to use Angular.JS to dynamically add columns to an html table.
It starts with a set of data, and I want to make extra data available on a click. I'm new to Angular, and made this plunker to illustrate what I'm trying to do. I'd like to (obviously) just add a new table header and a new table data based on the number of items in the array, matched to the index number of the same row. Thank you
Controller:
function Ctrl($scope) {
$scope.data = [];
$scope.data[3] = [];
$scope.data[0] = [['New York', 1000,2000],['Los Angeles', 200,400],['Nottingham', 800,400]]
$scope.moredata = [1500, 2500, 4500];
temp = []
$scope.getData = function() {
$scope.moduleArray[1] = $scope.moredata;
}
$scope.moduleArray = $scope.data;
}
HTML:
<div ng-controller="Ctrl">
<button ng-click="getData()">Get more data</button>
<table>
<tr>
<th>Location</th>
<th>Current Data</th>
<th ng-repeat="ba in moduleArray[1]">new data</th>
</tr>
<tr data-ng-repeat="item2 in moduleArray[0]">
<td>2[0]{{item2[0]}}</td>
<td>2[1]{{item2[1]}}</td>
<td data-ng-repeat="bat in moduleArray[1]">{{bat[$parent.$index]}}</td>
</tr>
</table>
Plunkr
Here's very simple set up that toggles single columns on right side.
There are 2 sets of arrays, one for column headers and one for row data.
It uses limitTo filter for ng-repeat.
From there it is a simple increment/decrement of a scope variable colCount to add/remove column
View
<button ng-click="increment('up')">Add Column</button>
<button ng-click="increment('down')">Remove Column</button>
<table class="table table-bordered">
<tr>
<th ng-repeat="col in cols | limitTo: colCount">{{col}}</th>
</tr>
<tr ng-repeat="row in data">
<td ng-repeat="item in row | limitTo: colCount">{{item}}</td>
</tr>
</table>
Controller
// used as limit for ng-repeat limitTo
$scope.colCount = 3;
$scope.increment = function(dir) {
(dir === 'up') ? $scope.colCount++: $scope.colCount--;
}
$scope.cols = // array of column names
$scope.data = // row data arrays
Note that for large tables this may not great for performance due to multiple nested repeaters
DEMO
I'm trying to use jQuery to capture the value of two cells from a table. My table looks like this:
<table id="searchByLocationResults" class="table table-hover table-striped" cellspacing="0" style="border-collapse:collapse;">
<tbody>
<tr>
<th scope="col">View Detail</th>
<th scope="col">Quantity</th>
<th scope="col" style="display:none;">Location ID</th>
<th scope="col" style="display:none;">Item Type ID</th>
</tr>
#For Each item In Model
Dim currentItem = item
#<tr>
<td><a class="btn btn-default btn-sm" onclick="viewDetails(this)">View Detail</a></td>
<td>
#Html.DisplayFor(Function(modelItem) currentItem.COUNT)
</td>
<td style="display:none;" class="locationID">
#Html.DisplayFor(Function(modelItem) currentItem.Unique_Location_ID)
</td>
<td style="display:none;" class="itemType">
#Html.DisplayFor(Function(modelItem) currentItem.Item_Type_Identifier)
</td>
</tr>
Next
</tbody>
</table>
As you can see there is a 'view details' button on each row. What I need to do is capture the display:none values in the cells with class=locationID and class=itemType when the button is clicked, only for the row that the button is clicked on. I have seen multiple solutions on stack over flow here, here and quite a few others. Most of these are dealing with capturing an entire row of values.
I have tried a few different scripts:
function viewDetails(clickedRow) {
var locationID = $(this).find(".selected td:.locationID").val();
alert(locationID);
and:
function viewDetails(clickedRow) {
var locationID = tr.find(".locationID").val();
alert(locationID);
as well as a few others.
How do you capture the values of the cells locationID and itemType for the row that 'View Details' is clicked on?
I would say to try the index. This only works if the buttons and text areas have unique classes so the count works correctly. Then once you have the index use the eq() to get the data.
var index = $(".btn-sm").index();
var locationId = $(".locationID").eq(index).text();
You are almost there. You just need to use the .text() method in Jquery
function viewDetails(clickedRow) {
var locationID = tr.find(".locationID").text();
alert(locationID);
I'm trying to sort a table by each column. The table has a different amount of rows and columns each time. The problem is with the predicate. All of the repeated columns are name "i", and I need to be able to sort them individually.
HTML:
<table>
<thead>
<th>name</th>
<th ng-repeat="header in headers">{{header}}</th>
</thead>
<tbody>
<tr ng-repeat="v in columns | orderBy:predicate:reverse">
<td>{{v.value}}</td>
<td ng-repeat="i in v.item">{{i}}</td>
</tr>
</tbody>
</table>
Controller:
function controller($scope) {
$scope.headers = ["col1", "col2", "col3", "col4"];
$scope.columns = [{value:'row1', item:['1','2','3','4']},
{value:'row2', item:['4','5','6','7']},
{value:'row3', item:['8','9','10','11']},
{value:'row4', item:['12','13','14','15']}];
$scope.predicate = 'value';
}
Here is the jsfiddle.
Thanks for the replies.
Change the statement like this
<th ng-repeat="header in headers">
{{header}
</th>
Note: Since the cells are all strings, this will sort all columns as string alphabetically.
Hope it can shed some light on.
Demo