I am generating following json data from my database where keys like sid and name is static but task1,task2,task3 .... are dynamic and they can be upto value n(where n=1,2,3......)
My data:
[
{"sid":"10","name":"nam1","task1" :"1","task2" :"0","task3" :"1","task4" :"0","task5" :"0"},
{"sid":"20","name":"nam2","task1" :"0","task2" :"1","task3" :"0","task4" :"1","task5" :"1"},
{"sid":"30","name":"nam3","task1" :"1","task2" :"1","task3" :"0","task4" :"0","task5" :"1"},
{"sid":"40","name":"nam4","task1" :"0","task2" :"0","task3" :"0","task4" :"0","task5" :"1"}
]
app.js
app.controller('taskCrtl', function ($scope, $http, $timeout) {
$http.get('get.php').success(function(data){
$scope.list = data;
$scope.currentPage = 1; //current page
$scope.entryLimit = 5; //max no of items to display in a page
$scope.filteredItems = $scope.list.length; //Initially for no filter
$scope.totalItems = $scope.list.length;
});
Now i am trying to access key values using ng-repeat like below:
<tr ng-repeat="data in list| unique: 'sid'">
<td>{{data.sid }}</td>
<td>{{data.name}}</td>
<td>{{data.task1}}</td>
<td>{{data.task2}}</td>
<td>{{data.task3}}</td>
<td>{{data.task4}}</td>
<td>{{data.task5}}</td>
<tr/>
The above code works well for fixed keys like task1,task2,task3... but i am generating "task" key dynamically so it will be always unknown to me that how many task keys are there.There may be a case when there are keys from task1 to task100 so the above code will fail on that case.
I am trying to dynamically access the task keys to generate associate data.To achieve this i am concatenating a number( produced by an incremental loop) with the task key so that i becomes like task1,task2 .... value n
<tr ng-repeat="data in list| unique: 'sid'">
<td> {{ data.sid }} </td>
<td> {{ data.name }} </td>
<td ng-repeat="data in list| limitTo:n">
{{ id=$index+1; 'data.task'+id}}
</td>
</tr>
Id starts with 1 and incremented in every loop so that we can dynamically access data.task1,data.task2 and so on
I am facing two problems here.After concatenation i was supposed to get the value of a corresponding task key but i am getting like this data.task1,data.task2,data.task3 that is i am getting keys itself instead of key values.
The second problem is i want to loop up to n number of times so i am limiting the ng-repeat by n like this way ng-repeat="data in list| limitTo:n" but the value of n is unknown to me.Here n should be equal to the highest number of dynamic task key(or total task keys).
For example if in the data list there exist task1,task2,task3,task4,task5 then n will be 5 since there are total 5 task keys.If there exist task1 to task100 then n will be 100 as there are total 100 task keys.
One idea to achieve this could be counting total unique keys from the array and then subtract 2 static keys from it to get the number of dynamic keys which will be used as value of n to limit the loop.
For example in above data set the unique keys are sid,name,task1,task2,task3,task4,task5 if somehow we can manage to calculate total number of unique keys from the array then the total number of unique keys will be 7 in this case, and if we subtract 2 from the number 7 then we have 5 which is equal to the number of dynamic keys in the array, that we want to use as n to limit the loop.
Any idea how to solve my above problems using angularjs ?
I assume that the total number of task attributes on an Item may be varied.
By returning the list of Keys which start with Task you can iterate over that list instead and making it a function, you can call that during each iteration of ngRepeat:
$scope.getTaskKeys = function(row) {
return Object.keys(row).filter(function(keyname) {
return keyname.startsWith('task');
});
Leaving you free to call it as the collection for the second iteration:
<tr ng-repeat="data in list| unique: 'sid'">
<td> {{ data.sid }} </td>
<td> {{ data.name }} </td>
<td ng-repeat="taskKey in getTaskKeys(data)">
{{data[taskKey]}}
</td>
</tr>
Created a working example here: https://jsfiddle.net/zd1yjc0m/
Try this it will work as per your expectation..
var myApp = angular.module('myApp',[]);
myApp.controller('MyCtrl', function($scope) {
$scope.list = [
{"sid":"10","name":"nam1","task1" :"1","task2" :"0","task3" :"1","task4" :"0","task5" :"0"},
{"sid":"20","name":"nam2","task1" :"0","task2" :"1","task3" :"0","task4" :"1","task5" :"1"},
{"sid":"30","name":"nam3","task1" :"1","task2" :"1","task3" :"0","task4" :"0","task5" :"1"},
{"sid":"40","name":"nam4","task1" :"0","task2" :"0","task3" :"0","task4" :"0","task5" :"1"}
];
for (var i in $scope.list) {
var res = Object.keys($scope.list[i]).filter(item => { return item.indexOf("task") > -1; });
$scope.tasksList = res;
}
});
table,td {
border: 1px solid black;
padding: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
<table>
<tr ng-repeat="data in list">
<td> {{ data.sid }} </td>
<td> {{ data.name }} </td>
<td ng-repeat="item in tasksList"> {{ data[item] }} </td>
</tr>
</table>
</div>
data[0] contain the JSON data and data[1] contain dynamic key
<tr ng-repeat="x in data[0] ">
<td ng-repeat="j in data[1]">
[[ x[j] ]]
</td>
</tr>
Related
Trying to loop over an array and display the results, but only the last element showing multiple times.
Here is my code.
Making a get request.
showItems(id: any): Observable<any> {
return this.http.get(`${this.url}${id}`)
}
Console logging works fine here, I can see the expected results.
ngAfterViewInit(): void {
this.showItems()
}
showItems(): void {
const id: any = []
this.idFromList.forEach((val: any) => id.push(val.nativeElement.innerText))
for(let i = 0; id.length > i; i++) {
this.ItemService.showItems(id[i]).subscribe(data => {this.api_items = data.item.current
console.log(this.api_items)});
}
}
HTML
<table>
<thead>
<tr>
<td>Name</td>
<td>Price</td>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of items | filter: searchQuery" >
<td >
<a href="" #btn>{{item.id}}</a>
{{ item.name }}
</td>
<td *ngFor="let api_item of api_items | keyvalue">
{{ api_item.value }}
</td>
</tr>
</tbody>
</table>
Tried using fake JSON server, same results.
1) Quick answer
Push items in an array instead of replacing its value :
api_items = [];
this.ItemService.showItems(id[i]).subscribe(data => {
this.api_items.push(data.item.current);
});
2) Complete answer
As #MoxxiManagarm said, you're replacing api_items value at each iteration of your for loop.
You might want to check & use RxJS to handle multiple observables in a cleaner way: for example, by generating an array of Observable to resolve them together.
3) Ressources & useful links you might want to check for more information
https://www.learnrxjs.io/
I am trying to update quantity number of individual items in a table whenever the user clicks the item in another table.
For example, I have list of all items in Table A
<tr ng-repeat="item in items">
<td>{{item.fid}}</td>
<td{{ item.fname }}</td>
<td>{{ item.calorie }}</td>
<td>{{ item.protein }}</td>
<td>{{ item.carb }}</td>
<td>{{ item.fat }}</td>
<td><button ng-click=additem(values)>Add</button>
<tr>
Now when the user clicks this Add button, the selected item gets added to another table (Table B).
I have disabled duplicates in Table B and want that if the user is repeatedly adding same item then the quantity of the item in Table B should increase.
Table B
<tr ng-repeat="sitem in sitems>
<td>{{sitem.fname}}</td>
<td>{{sitem.calorie}}</td>
<td>{{sitem.protein}}</td>
<td>{{sitem.carb}}</td>
<td>{{sitem.fat}}</td>
<td>*</td>
<td><button ng-click="removeItem(values)">Remove</button></td>
</tr>
is the one where i want the increased quantity to be shown.
I have tried using "this" keyword but didn't worked, I am new to angular so i don't know what all are my options and got mixed up.
You have to keep track of two separate array to accomplish this.
This is the code snippet: `
$scope.additem = function(item) {
var index = $scope.sitems.indexOf(item);
if (index === -1) {
item.quantity = 1;
$scope.sitems.push(item);
return;
}
item.quantity++;
$scope.sitems[index] = item;
};
`
Complete Working fiddle: https://jsfiddle.net/nbakliwal18/4kbo7Lfo/2/
Also you check for quantity before adding.
You can simply pass item to the function addItem() :
<td><button ng-click=addItem(item)>Add</button>
and push this item to your array sitems in your function :
$scope.addItem = function(item) {
$scope.sitems.push(item);
}
A workaround for the duplicates in ng-repeat is to add track by $index to it :
<tr ng-repeat="sitem in sitems track by $index">
Update 1:
Updated my answer with working example in Plunker
Update 2:
Here is an example with lodash for quantity Plunker
I use angularjs in my project.
I want to filter my array in ng-repeat.
Here is HTML:
<tbody>
<tr ng-repeat="sensorData in list.sensorsData |
filterByAlert:list.alertTags">
<td>
<div class="container-fluid">
<div class="row">
<div class="text-center">{{ sensorData.Area }}</div>
</div>
</div>
</td>
</tr>
</tbody>
Here is how looks list.sensorsData array of objects:
Here is how looks list.alertTags array of objects:
I need to show in ng-repeat elements only list.sensorsData rows that has alertType properties value equal to Id proiperty in list.alertTags.
for this purpose I wrote this filter:
(function () {
"use strict";
angular.module("sensorsData").filter('filterByAlert', filterByAlert);
function filterByAlert() {
var result = [];
return function (sensorRecords, alertTypes) {
if (!sensorRecords)
return;
if (!alertTypes)
return;
angular.forEach(sensorRecords, function (sensorRecord, key) {
angular.forEach(alertTypes, function (alertType, key2) {
if (sensorRecord.AlertType == alertType.Id ) {
result.push(sensorRecord);
}
})
});
return result;
}
};
})();
but when filter is fired I get this error:
angular.js:13424 Error: [ngRepeat:dupes] Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: sensorData in list.sensorsData |
filter:filterByAddress |
orderBy:sortType:sortReverse |
filterByAlert:list.alertTags, Duplicate key: object:8, Duplicate value: {"Id":8,"Address":"125 king g.str","AlertType":3,"Area":"North","MeasureDate":"2012-10-12T16:10:00","MeasureValue":-1}
It seems I have problem with logic in my custom filter.
Any idea why I get the error?And how to fix it?
Add track by $index to your ng-repeat.
<tr ng-repeat="sensorData in list.sensorsData | filterByAlert:list.alertTags track by $index">
I am getting some data from an external service and I am trying to show it on a table. The problem is that the data I get from service will be with dynamic columns, some times there will be 5 column another time 8. I don't know how I could handle it in ng-repeat. and using things like ng-grid won't be a good solution I think as there will be only 10 rows to display. for this If I use any external solution that will be a overhead. Is there any angular method to achieve this? if not what is the best option for this small data.
Note: Column names will also be dynamic
My code
<div ng-app='myApp' ng-controller="MainCtrl">
<div ng-repeat="prdElement in packageElement track by $index" class="package-grid">
<table class="hovertable">
<thead>
<tr>
<th>Line #</th>
<th>Quantity in Plt</th>
<th>Allready Packed</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="data in prdElement.Data" ng-init="data.newquantity = 0">
<td>{{data.itemId}}</td>
<td>
{{data.quantity}}
</td>
<td>{{data.packed}}</td>
</tr>
</tbody>
</table>
</div>
angular.module('myApp', []).controller('MainCtrl', function ($scope) {
var counter = 0;
$scope.packageElement = [{
name: counter,
show: true,
Data: [{
name: 'item 1',
itemId: '284307',
quantity: '100',
packed: 0
}, {
name: 'item 2',
itemId: '284308',
quantity: '200',
packed: 0
}]
}];
});
Will there be the same number of columns for all data items? If so, I think you can do this.
1. Define a function on your scope that gives you the object keys:
$scope.keys = function(obj) {
var key;
var keys = [];
for (key in obj) {
if (key === "$$hashKey") break; //angular adds new keys to the object
if (obj.hasOwnProperty(key)) keys.push(key);
}
return keys;
}
2. use a repeater on the table header (if the objects can have different properties, you need to find the object with the highest number of properties/columns)
<th ng-repeat="key in keys( prdElement.Data[0] )">{{key}}</th>
3. use a repeater on the table cell
<td ng-repeat="key in keys( prdElement.Data[0] )">{{ data[key] }}</td>
In the view of a directive I have two ng-repeats.
This directive builds a table, and the data of every table cell is from another datasource.
This datasource needs the cumulative index of the two repeaters.
selectedKandidaat.AntwoordenLijst[$index].Value
I only have got the current $index, or the $parent.$index. So to keep track of the overall index that I want to use in Antwoordenlijst[$index] I will need to keep track of an index variable. Can I just use create and update an index variable in the view.
Something like this:
..
{{ totalIndex = 0 }}
<tr ng-repeat="opgave in opgaven">
<td ng-repeat="item in opgave.Items">
{{ totalIndex += 1 }}
..
The actual code
<table class="table">
<tr ng-repeat="opgave in opgaven">
<td ng-repeat="item in opgave.Items">
<select ng-model="selectedKandidaat.AntwoordenLijst[$index].Value"
ng-options="alternatief for alternatief in item.Alternatieven">
</select>
</td>
</tr>
</table>
Each ng-repeat creates it's own scope, so to find the total count you need count in the parent scope.
<div ng-repeat="a in items1">
parent: {{$index}}
<div ng-repeat="b in items2" itemcell>
child: {{$index}}
total: {{totalCount}}
</div>
</div>
total: {{totalCount}}
and counter in new itemcell derective
app.directives
.directive('itemcell', function () {
return {
restrict: 'A',
link: function ($scope, iElement, iAttrs) {
if (!$scope.$parent.$parent.totalCount) {
$scope.$parent.$parent.totalCount = 0;
}
$scope.$parent.$parent.totalCount++;
}
}
})
You also can try to count current index via $parent.$index, but it works only if you have collections with the same items count.