Using ng-repeat on nested array of objects - angularjs

Below is my JSON object and I am trying to show the same in html table.
$scope.results = {
"data": [
{
"name": "Sam",
"details": [
{
"official": [
{
"address1": "Link road",
"pincode": 76755554
},
{
"address1": "K main road",
"pincode": 9766565
}
]
},
{
"name": "John",
"details": [
{
"official": [
{
"address1": "Old college road",
"pincode": 11111
},
{
"address1": "near east side",
"pincode": 6555446
}
]
}
]
}
]
}
]
}
I have used ng-repeat to achieve the below output. But I am not getting the expected result
This is the code which I have tried and got stuck JSFIDDLE
Any idea on how to achieve my expected result will be really helpful.

You may have to tweak this slightly if your data structure can get more complicated when there are more levels, but this should reformat your data and flatten everything into an array of people without all the different levels.
$scope.peopleFlat = [];
function flattenPeople(people) {
people.forEach((person) => {
$scope.peopleFlat.push({
name: person.name,
addresses: person.details[0].official
});
if (person.details.length > 1) {
flattenPeople([person.details[1]]);
}
});
}
flattenPeople($scope.people);
Then you can use a combination of ng-repeat-start and ng-repeat-end to make it work using rowspan instead of a nested <table> element.
<table class="table table-bordered table-condensed">
<tr>
<th>Name</th>
<th>Address</th>
<th>Pincode</th>
</tr>
<tr ng-repeat-start="person in peopleFlat">
<td rowspan="{{person.addresses.length || 1}}">{{person.name}}</td>
<td>{{person.addresses.length ? person.addresses[0].address1 : ''}}</td>
<td>{{person.addresses.length ? person.addresses[0].pincode : ''}}</td>
</tr>
<tr ng-repeat-end ng-repeat="address in person.addresses.slice(1)">
<td>{{address.address1}}</td>
<td>{{address.pincode}}</td>
</tr>
</table>

Related

Angular 2 How to Concatenate an index into an object and its array using Ng For

I dynamically created an array using rows and columns
[
{
"name": "table 1",
"rows": [
"row 1",
"row 2",
"row 3",
"row 4",
"row 5"
],
"columns": [
"column 1",
"column 2"
],
"col1": [
{
"1": "row1col1"
},
{
"2": "row2col1"
},
{
"3": "row3col1"
},
{
"4": "row4col1"
},
{
"5": "row5col1"
}
],
"col2": [
{
"1": "row1col2"
},
{
"2": "row2col2"
},
{
"3": "row3col2"
},
{
"4": "row4col2"
},
{
"5": "row5col2"
}
]
},
{
"name": "table 2",
"rows": [
"row 1",
"row 2",
],
"columns": [
"column 1",
"column 2",
"column 3"
],
"col1": [
{
"1": "row1col1"
},
{
"2": "row2col1"
],
"col2": [
{
"1": "row1col2"
},
{
"2": "row2col2"
],
"col3": [
{
"1": "row1col3"
},
{
"2": "row2col3"
]
}
]
Then using this dynamic array I created a table and stored it as finalArray
which was okay until I went to the body of my table to show data for col and row
<div *ngFor="let table of finalArray">
<span>{{table.name}}</span>
<table class="table">
<thead class="thead-dark">
<tr>
<th scope="col"></th>
<th *ngFor="let column of table.columns" scope="col">{{column}}</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let row of table.rows ; let i = index">
<td>{{row}}</td> // this works fine
<td *ngFor="let column of table.columns; let x = index"> {{table.['col' + x].[i+1]}}</td>
// this is the problem
</tr>
</tbody>
</table>
</div>
Note that the array was created dynamically so rows and columns is not fixed and col1 and col2 was created based on columns.
I attempt to something like table.col[index].[loop all values]?
You are almost there. Iterate thru columns in the second loop for more precision. Remove '.'s when getting elements. Interchange + 1 from i to x when getting columns and use Object.keys to get the array of key names so you can get the corresponding column content. I put it in a method for for readability
HTML
<table class="table">
<thead class="thead-dark">
<tr>
<th scope="col"></th>
<th *ngFor="let column of table.columns" scope="col">{{column}}</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let row of table.rows ; let i = index">
<td>{{row}}</td>
<td *ngFor="let col of table.columns; let x = index">
{{getColumnContent(table['col'+(x+1)][i])}}
</td>
</tr>
</tbody>
</table>
Typescript
getColumnContent(col) {
return col[Object.keys(col)[0]] // always [0] as it contains a single element
}
Demo

how to get particular customers order

/*factory method for getting particular customers order*/
factory.getCustomer = function(customerId) {
for(var i=0,len=customers.length ; i<len ; i++) {
if(customers[i].id === parseInt(customerId)){
return customer[i];
}
}
return {};
};
return factory();
/*Controller*/
myApp.controller('OrdersController',['$scope','$routeParams','customersFactory', function($scope,$routeParams,customersFactory) {
var customerId = $routeParams.customerId;
$scope.customer = null;
function init() {
$scope.customer = customersFactory.getCustomer(customerId);
}
init();
}]);
/*View*/
<div class="container">
<div class="row">
<div class="col-md-12">
<h2>{{customer.name}}'s Orders</h2>
<table class="table table-hover">
<tr>
<th>Product</th>
<th>Total</th>
</tr>
<tr ng-repeat="order in customer.orders">
<td>{{ order.product }}</td>
<td>{{ order.total | currency }}</td>
</tr>
</table>
</div>
</div>
</div>
/*JSON FILE*/
{
"id": "1",
"joined": "2000-12-2",
"name": "Wali",
"city": "Dubai",
"orderTotal": "9.0765",
"orders": [
{
"id": "1",
"product": "protein",
"total": "11.987"
}
]
},
{
"id": "2",
"joined": "2004-12-2",
"name": "Ali",
"city": "London",
"orderTotal": "20.0765",
"orders": [
{
"id": "2",
"product": "bcca",
"total": "2.3456"
},
{
"id": "3",
"product": "baseball",
"total": "4.3456"
}
]
},
{
"id": "3",
"joined": "1980-11-2",
"name": "Zen",
"city": "Australia",
"orderTotal": "6.500",
"orders": [
{
"id": "3",
"product": "chocolate",
"total": "6.4567"
}
]
}
I have made a customers table from which we can perform the CRUD functionality, but when I click to check the particular customer order it is redirecting me to the right view via routing but particular customers orders are not displaying.
can any one suggest a solution for this?
According to your JSON data, the ID is a String, but you are parsing it into an integer, and using ===, which will match only if the value and the type of the compared variables match.
You need to change the if statement, one option is:
if (parseInt(customers[i].id) === parseInt(customerId))
Another option will be:
if (customers[i].id == customerId)
And yet another option is using angular's $filter service.
You need to inject it into your factory, and than in order to get the client, you can use:
var customer = $filter('filter')(customers, {id: customerId.toString()}, true);
return customer.length === 1 ? customer[0] : null;
The toString part is only because your JSON data have ID as as string, and the third argument is set to true to prevent 'like' filter (default $filter behavior will return id 10 for example also if the customerId is 1).

AngularJS - How do I filter an array of 'deep' objects given an array of values to filter by?

I am trying to filter my data which I am getting from a HTTP GET endpoint by an array of values
filters = ['Full Time', 'LinkedIn', ...]
The general structure of the response I am getting back is an array of objects where each object can look like this:
{
"preferences": {
"jobType": {
"type": "Full Time"
}
},
"profile": {
"additionalinfo": {
"organization": [
{
"name": "Google"
},
{
"name": "LinkedIn"
}
],
"university": [
{
"name": "UC Berkeley",
"degrees": [ {"name": "Computer Engineering"}]
}
}
}
}
So if I filter by ["Google", "Full Time"], the above object should be included.
Is there a built in filter to handle this?
I am having trouble writing the custom filter to handle such a heavily nested object.
Any ideas on how to implement this?
You can use built in filter like this jsfiddle
var myApp = angular.module("myApp", []);
myApp.controller("myCtrl", function($scope) {
$scope.data = [{
"preferences": {
"jobType": {
"type": "Full Time"
}
},
"profile": {
"additionalinfo": {
"organization": [{
"name": "Google"
}, {
"name": "LinkedIn"
}],
"university": [{
"name": "UC Berkeley",
"degrees": [{
"name": "Computer Engineering"
}]
}]
}
}
}, {
"preferences": {
"jobType": {
"type": "Remote"
}
},
"profile": {
"additionalinfo": {
"organization": [{
"name": "Yandex"
}, {
"name": "LinkedIn"
}],
"university": [{
"name": "UC Berkeley",
"degrees": [{
"name": "Computer Engineering"
}]
}]
}
}
}];
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.min.js"></script>
<body ng-app="myApp" ng-controller="myCtrl">
<h3>Jobs</h3>
<input ng-model="filterModelJobType" placeholder="filter jobType">
<input ng-model="filterModelJob" placeholder="filter job">
<table class="table table-striped table-bordered">
<tbody>
<tr ng-repeat="x in data|filter:{profile: {additionalinfo:{organization:{name:filterModelJob}}},preferences: {jobType:{type:filterModelJobType}}}">
<td>{{ $index + 1 | number }}</td>
<td class="text-center">{{ x.preferences.jobType.type }}</td>
<td class="text-left">
<div ng-repeat="org in x.profile.additionalinfo.organization">
<hr> {{org.name}}
</div>
</td>
</tr>
</tbody>
</table>
</body>
In the latest version of AngularJS
If there is nested object then
var foo = $filter('filter')($scope.welcome, {
additionalinfo: { name: 'google' }
});
Reference: GitHub issue

Get value in a row on click and pass it to popup

I need to get the value in a row of a table on click and display it in popup
HTML:
<md-data-table-container>
<table md-data-table class="md-primary" md-progress="deferred">
<thead md-order="query.order" md-trigger="onorderchange">
<tr>
<th name="Task To Be Done"></th>
<th name="Office"></th>
<th name="Due Date"></th>
</tr>
</thead>
<tbody ng-click="showAlert($event)">
<tr ng-repeat="dessert in desserts.data" ng-click="showAlert($index)" flex-sm="100" flex-md="100" flex-gt-md="auto">
<td>{{dessert.task}}</td>
<td></td>
<td>{{dessert.due_on}}</td>
</tr>
</tbody>
</table>
</md-data-table-container>
JS:
$scope.desserts = {
"count": 6,
"data": [{
"task": "Frozen yogurt",
"type": "Ice cream"
}, {
"task": "Ice cream sandwich",
"type": "Ice cream"
}, {
"task": "Eclair",
"type": "Pastry"
}, {
"task": "Cupcake",
"type": "Pastry"
}, {
"task": "Jelly bean",
"type": "Candy"
}, {
"task": "Lollipop",
"type": "Candy"
}, {
"task": "Honeycomb",
"type": "Other"
}]
};
$scope.showAlert = function (index) {
$scope.obj = $scope.desserts.data[2];
$scope.task = $scope.obj.task;
alert($scope.task);
console.log($scope.task);
};
issue in my code is that i could get the value on the array which i have specified ".data[2]". Actually when i click a row in my table i need that value to be displayed to popup "sweetAlert". is there any solution
Don't pass the $index, as this can be a bit dangerous if the underlying data changes, and in this case it just forces you to re-get the item from the array.
Pass the actual item you want to display back to the alert.
<tr ng-repeat="dessert in desserts.data" ng-click="showAlert(dessert)" flex-sm="100" flex-md="100" flex-gt-md="auto">
<td>{{dessert.task}}</td>
<td></td>
<td>{{dessert.due_on}}</td>
</tr>
Don't assign to scope unless you really need it elsewhere.
$scope.showAlert = function (dessert) {
alert('Task:' + dessert.task);
// if you're just using a variable in this function, declare it locally
var dessertType = dessert.type;
console.log(dessertType);
};
See an example of $index causing issues:
http://codeutopia.net/blog/2014/11/10/angularjs-best-practices-avoid-using-ng-repeats-index/comment-page-1/

Draw a matrix array based in AngularJS

I need to draw a table in AngularJS based on the following array
$scope.list = [
{ "Row":1, "Column": 1, "Value": "11" },
{ "Row":1, "Column": 2, "Value": "12" },
{ "Row":1, "Column": 3, "Value": "13" },
{ "Row":2, "Column": 1, "Value": "21" },
{ "Row":2, "Column": 2, "Value": "22" },
{ "Row":2, "Column": 3, "Value": "23" },
];
So I need to get a table with 2 rows and 3 columns
I understand that I have to use two nested ngRepeat but I couldn't make it work
Please could you help me ??
Regards
I developed the solution I found a filter 'Unique' here
For each unique row number I get the list of columns
<table border="2">
<tr ng-repeat="row in list | unique:'Row'">
<td>Row: {{row.Row}}</td>
<td ng-repeat="col in list | filter:{'Row':row.Row}">{{col.Value}}</td>
</tr>
</table>
You should first transform your array to such one:
$scope.table = [
["11", "12", "13"],
["21", "22", "23"],
];
That way, it will be easier to iterate over the values in your view:
<table>
<tr ng-repeat="row in table">
<td ng-repeat="column in row">
{{column}}
</td>
</tr>
</table>

Resources