Nested ng-repeat in Angular JS table - javascript

I am a newbie to Angular JS.
I have been trying iterate through a model collection and display the same in a table.
The Model looks like :
var myModule = angular
.module("myModule", [])
.controller("myController", function ($scope) {
var countries = [
{
name: "UK",
cities: [
{name: "London"},
{name: "Birmingham" },
{name: "Manchestar" }
],
flag:"/Images/UK.gif"
},
{
name: "USA",
cities: [
{name: "Los Angeles"},
{name: "Houston"},
{name: "Florida"},
],
flag:"/Images/USA.png"
}
];
$scope.countries = countries;
});
And I want the table structure to be
Country City1 City2 City3 Flag
UK London Birmingham Manchestar .....
USA ...... ......... ......... .....
But I could not do the same in the html page.
So far the code looks like :
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" ng-app="myModule">
<head>
<title></title>
<script src="Scripts/angular.js"></script>
<script src="Scripts/MyModuleScript.js"></script>
</head>
<body ng-controller="myController">
<div>
<table>
<thead>
<tr>
<th>Country</th>
<th>City 1</th>
<th>City 2</th>
<th>City 3</th>
<th>Flag</th>
</tr>
</thead>
<tbody ng-repeat="country in countries">
<tr ng-repeat="city in country.cities">
<td>{{ country.name }}</td>
<td>
{{......}}
</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
What I need to do to achieve the same ? Please explain.

try this. you must put ng-repeat on td instead of row.
var myModule = angular
.module("myModule", [])
.controller("myController", function ($scope) {
$scope.countries = [
{
name: "UK",
cities: [
{name: "London"},
{name: "Birmingham" },
{name: "Manchestar" }
],
flag:"/Images/UK.gif"
},
{
name: "USA",
cities: [
{name: "Los Angeles"},
{name: "Houston"},
{name: "Florida"},
],
flag:"/Images/USA.png"
}
];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myModule" ng-controller="myController">
<div>
<table>
<thead>
<tr>
<th>Country</th>
<th>City 1</th>
<th>City 2</th>
<th>City 3</th>
<th>Flag</th>
</tr>
</thead>
<tbody ng-repeat="country in countries">
<tr>
<td>{{ country.name }}</td>
<td ng-repeat="city in country.cities">
{{city.name}}
</td>
<td><img ng-src="{{country.flag}}"></td>
</tr>
</tbody>
</table>
</div>
</div>

repeat a little and it works as you need it.
<tbody ng-repeat="country in countries">
<tr >
<td >{{ country.name }}</td>
<td ng-repeat="city in country.cities">
{{city.name}}
</td>
<td><img ng-src="{{country.flag}}"></td>
</tr>
</tbody>
var myModule = angular
.module("myModule", [])
.controller("myController", function ($scope) {
var countries = [
{
name: "UK",
cities: [
{name: "London"},
{name: "Birmingham" },
{name: "Manchestar" }
],
flag:"/Images/UK.gif"
},
{
name: "USA",
cities: [
{name: "Los Angeles"},
{name: "Houston"},
{name: "Florida"},
],
flag:"/Images/USA.png"
}
];
$scope.countries = countries;
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" ng-app="myModule">
<head>
<title></title>
<script src="Scripts/angular.js"></script>
</head>
<body ng-controller="myController">
<div>
<table>
<thead>
<tr>
<th>Country</th>
<th>City 1</th>
<th>City 2</th>
<th>City 3</th>
<th>Flag</th>
</tr>
</thead>
<tbody ng-repeat="country in countries">
<tr >
<td >{{ country.name }}</td>
<td ng-repeat="city in country.cities">
{{city.name}}
</td>
<td><img ng-src="{{country.flag}}"></td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
var myModule = angular
.module("myModule", [])
.controller("myController", function ($scope) {
var countries = [
{
name: "UK",
cities: [
{name: "London"},
{name: "Birmingham" },
{name: "Manchestar" }
],
flag:"/Images/UK.gif"
},
{
name: "USA",
cities: [
{name: "Los Angeles"},
{name: "Houston"},
{name: "Florida"},
],
flag:"/Images/USA.png"
}
];
$scope.countries = countries;
});

Everything is fine except your HTML.
Your first ng-repeat for countries should be for <tr>
The second one should be for <td>
tbody is not supposed to be repeated as seen by some of the answers here. As per w3c HTML5 Specs tbody tbody is single element after thead
You are on the right track just remember that ng-repeat will repeat the element on which it is specified as attribute.
<tbody>
<tr ng-repeat="country in countries">
<td >{{ country.name }}</td>
<td ng-repeat="city in country.cities">
{{city.name}}
</td>
<td><img ng-src="{{country.flag}}"></td>
</tr>
</tbody>

Related

How can I make Vue Sortable work on table?

I have an issue with this library. First of all, to test the library, I made a simple example work with ul and li tags. It was straightforward. Then, I needed to do a table, and when converting my example to a table it didn't work.
Table is showed but I cannot move any row.
I'm using the cdn way.
I think is something what I missing.
html
<div id='app-example-drag' >
<table class="table table-striped">
<thead class="thead-dark">
<tr>
<th scope="col">Id</th>
<th scope="col">Name</th>
<th scope="col">Sport</th>
</tr>
</thead>
<draggable v-model="list" tag="tbody">
<tr v-for="item in list" :key="item.name">
<td scope="row">{{ item.id }}</td>
<td>{{ item.name }}</td>
<td>{{ item.sport }}</td>
</tr>
</draggable>
</table>
</div>
js
Vue.component('draggable',vuedraggable);
applicationExample = new Vue({
el: '#app-example-drag',
display: "Table",
order: 8,
data() {
return {
list: [
{ id: 1, name: "Abby", sport: "basket" },
{ id: 2, name: "Brooke", sport: "foot" },
{ id: 3, name: "Courtenay", sport: "volley" },
{ id: 4, name: "David", sport: "rugby" }
]
};
}
});
https://jsfiddle.net/0Luhd694/3/
Thanks in advance
I just ran into this same problem. I think it has something to with recent version. Replace the draggable element with a tbody and make is='draggable'.
<div id='app-example-drag' >
<table class='table'>
<thead>
<tr><th scope='col'>description</th></tr>
</thead>
<tbody tag='tbody' v-model='lista1' is='draggable' group='items'>
<tr v-for='item in lista1' :key='item.id'>
<td scope='row'>{{item.description}}</td>
</tr>
</tbody>
</table>
</div>
https://jsfiddle.net/oqf64kdx/

AngularJS: ng-repeat not show items

I tried the code of AngularJS as follows:
var app = angular.module('MyApp', []);
app.controller('new_controller', function($scope) {
$scope.people= [{
name: "GeekAgashi",
Age: 12,
attended: 1
}, {
name: "GeekSatoshi",
Age: 16,
attended: 0
}, {
name: "GeekNakumato",
Age: 14,
attended: 1
}];
});
In HTML file the code:
<div class="sidebar-pane" ng-app="MyApp" id="flight_info" ng-controller="new_controller">
<table>
<tr>
<td>Name</td>
<td>Age</td>
</tr>
<tr ng-repeat="p in people">
<td>{{p.name}}</td>
<td>{{p.Age}}</td>
</tr>
</table>
</div>
On the webpage, I can only get the table frame which I think means that the data is successfully passed. But I cannot get the table items:
<table>
<tbody>
<tr>
<td>Name</td>
<td>Age</td>
</tr>
<!-- ngRepeat: p in people -->
<tr ng-repeat="p in people" class="ng-scope">
<td></td>
<td></td>
</tr>
<!-- end ngRepeat: p in people -->
<tr ng-repeat="p in people" class="ng-scope">
<td></td>
<td></td>
</tr>
<!-- end ngRepeat: p in people -->
<tr ng-repeat="p in people" class="ng-scope">
<td></td>
<td></td>
</tr>
<!-- end ngRepeat: p in people -->
</tbody>
</table>
I am just wondering if it is a bug or there is something wrong with my code, or the browser (chrome v79) does not support it.
Appendix:
I write the backend in Django and I found that if I directly run the plain HTML, the table is visible. The problem happens if I run it through a Django server. Since I am a green hand to the frontend, I am wondering if it is possible that the problem lies in the CSS file or the confliction with other local javascript?
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<body>
<div class="sidebar-pane" ng-app="MyApp" id="flight_info" ng-controller="new_controller">
<table>
<tr>
<td>Name</td>
<td>Age</td>
</tr>
<tr ng-repeat="p in people">
<td>{{p.name}}</td>
<td>{{p.Age}}</td>
</tr>
</table>
</div>
<script>
var app = angular.module('MyApp', []);
app.controller('new_controller', function($scope) {
$scope.people= [{
name: "GeekAgashi",
Age: 12,
attended: 1
}, {
name: "GeekSatoshi",
Age: 16,
attended: 0
}, {
name: "GeekNakumato",
Age: 14,
attended: 1
}];
});
</script>
</body>
</html>
Kindly check if the above code is running?
I copy & paste your code to the snipped (Angulerjs version 1.7.5) and it seems like it's working.
var app = angular.module('MyApp', []);
app.controller('new_controller', function($scope) {
$scope.people = [{
name: "GeekAgashi",
Age: 12,
attended: 1
}, {
name: "GeekSatoshi",
Age: 16,
attended: 0
}, {
name: "GeekNakumato",
Age: 14,
attended: 1
}];
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<div class="sidebar-pane" ng-app="MyApp" id="flight_info" ng-controller="new_controller">
<table>
<tr>
<td>Name</td>
<td>Age</td>
</tr>
<tr ng-repeat="p in people">
<td>{{p.name}}</td>
<td>{{p.Age}}</td>
</tr>
</table>
</div>
In your question you specify that you are using django. I assume that you are using it to retrieve the people data (correct me if I'm wrong). Can you please show us how you retrieve the data? This might just be a case of async operation, so the data isn't there at the time the page is rendered.
The reason is a confliction of django and angularJS templates. The solution could be find in this question.

How to handle nested structures with ng-repeat using HTML tables in Angular 1.x

Let us assume we have following data structure:
var data = [
{
name: "item name",
nestedData: [{
name: "nested name",
quantity: 1
},
{
name: "nested name 2",
quantity: 2
}
]
},
{
name: "item name 2",
nestedData: [{
name: "nested name 3",
quantity: 3
}
]
}
];
Standard behavior of ng-repeat directive will iterate over high level elements. If we run ng-repeat="item in data" it will produce two items.
Is it possible - without using custom directive - to iterate over first item ("item name") twice (multiply it by a length of nestedData array)?
The output I'd like to achieve is:
<table>
<thead>
<th>Name</th>
<th>Nested name</th>
<th>Nested quantity</th>
</thead>
<tbody>
<tr>
<td rowspan="2">item name</td>
<td>nested name</td>
<td>1</td>
</tr>
<tr>
<td ng-hide="true">item name</td>
<td>nested name 2</td>
<td>2</td>
</tr>
<tr>
<td>item name 2</td>
<td>nested name 3</td>
<td>3</td>
</tr>
</tbody>
</table>
Nested ng-repeat is not suitable in this situation because there's a need to iterate over <tr>'s.
You can use a nested ng-repeat to get your desired result as it's valid HTML to have multiple tbody elements.
Here is a JSFiddle for a working example
<table>
<thead>
<th>Name</th>
<th>Nested name</th>
<th>Nested quantity</th>
</thead>
<tbody ng-repeat="item in data">
<tr ng-repeat="nestedItem in item.nestedData">
<td rowspan="{{item.nestedData.length}}" ng-hide="$index == 1">{{item.name}}</td>
<td>{{nestedItem.name}}</td>
<td>{{nestedItem.quantity}}</td>
</tr>
</tbody>
</table>
It's a different approach to achieve expected output.
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
var data = [
{
name: "item name",
nestedData: [
{
name: "nested name",
quantity: 1
},
{
name: "nested name 2",
quantity: 2
},
{
name: "nested name 3",
quantity: 3
}
]
},
{
name: "item name 2",
nestedData: [{
name: "nested name 3",
quantity: 3
}
]
}
];
var nestedData = [];
angular.forEach(data, function(item){
if(item.nestedData.length > 1){
angular.forEach(item.nestedData, function(nestedItem){
nestedData.push({
name : item.name,
nestedName: nestedItem.name,
nestedQty: nestedItem.quantity,
colspan: item.nestedData.length
});
});
} else {
nestedData.push({
name : item.name,
nestedName: item.nestedData[0].name,
nestedQty: item.nestedData[0].quantity
});
}
});
$scope.data = nestedData;
});
tr.multiple > td:first-child {
display: none;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular.min.js"></script>
<div class="container" ng-app="myApp" ng-controller="myCtrl">
<table class="table table-stripped">
<thead>
<th>Name</th>
<th>Nested name</th>
<th>Nested quantity</th>
</thead>
<tbody>
<tr ng-repeat="item in data" ng-class="{'multiple': item.colspan > '1' && !$first}">
<td rowspan="{{item.colspan ? item.colspan : '1'}}">{{item.name}}</td>
<td>{{item.nestedName}}</td>
<td>{{item.nestedQty}}</td>
</tr>
</tbody>
</table>
</div>

ng-repeat does not work on Angular JS

I have created a controller (movies.js) as below-
'use strict';
angular.module('clientApp')
.controller('MoviesCtrl', function ($scope) {
$scope.movies = [
{
title:'Star Wars!',
url:'http://www.google.com'
},
{
title: 'Star Wars2!',
url: 'http://www.google.com'
},
{
title: 'Star Wars3!',
url: 'http://www.google.com'
}
];
});
Now I'm trying to access the values of each objects using ng-repeat in movies.html-
<table class="table table-striped">
<thead>
<th>Title</th>
<th>URL</th>
</thead>
<tbody>
<tr ng-repeat="movie in movies">
<td> {{ movie.title }} </td>
<td> {{ movie.url }} </td>
</tr>
</tbody>
</table>
However, the values are not populated as expected. Can someone please provide any tips on where should I look to fix it?
Since you are assigning the array to this so
var app = angular.module('my-app', [], function() {})
app.controller('AppController', function($scope) {
this.movies = [{
title: 'Star Wars!',
url: 'http://www.google.com'
}, {
title: 'Star Wars2!',
url: 'http://www.google.com'
}, {
title: 'Star Wars3!',
url: 'http://www.google.com'
}];
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="my-app">
<div ng-controller="AppController as ctrl">
<table class="table table-striped">
<thead>
<th>Title</th>
<th>URL</th>
</thead>
<tbody>
<tr ng-repeat="movie in ctrl.movies">
<td>{{ movie.title }}</td>
<td>{{ movie.url }}</td>
</tr>
</tbody>
</table>
</div>
</div>
Or assign the array to the scope variable
var app = angular.module('my-app', [], function() {})
app.controller('AppController', function($scope) {
$scope.movies = [{
title: 'Star Wars!',
url: 'http://www.google.com'
}, {
title: 'Star Wars2!',
url: 'http://www.google.com'
}, {
title: 'Star Wars3!',
url: 'http://www.google.com'
}];
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="my-app">
<div ng-controller="AppController">
<table class="table table-striped">
<thead>
<th>Title</th>
<th>URL</th>
</thead>
<tbody>
<tr ng-repeat="movie in movies">
<td>{{ movie.title }}</td>
<td>{{ movie.url }}</td>
</tr>
</tbody>
</table>
</div>
</div>
You should try this
'use strict';
angular.module('validationApp' ,[])
.controller('MoviesCtrl', function ($scope) {
$scope.movies = [
{
title:'Star Wars!',
url:'http://www.google.com'
},
{
title: 'Star Wars2!',
url: 'http://www.google.com'
},
{
title: 'Star Wars3!',
url: 'http://www.google.com'
}
];
});
it should be
<table class="table table-striped">
<thead>
<th>Title</th>
<th>URL</th>
</thead>
<tbody>
<tr ng-repeat="movie in MoviesCtrl.movies">
<td> {{ movie.title }} </td>
<td> {{ movie.url }} </td>
</tr>
</tbody>
</table>
or you should bind it to $scope.movies
Still you won't be able to load external URLs. You need to make a filter to whitelist the external links. Refer below code.
angular.module('myApp')
.filter('trustUrl', function ($sce) {
return function(url) {
return $sce.trustAsResourceUrl(url);
};
});
<td> {{ movie.url | trustUrl}} </td>
You need to inject $scope into your controller, and use that to bind your array to your view
.controller('MoviesCtrl', function($scope){
$scope.movies = [
{
title:'Star Wars!',
url:'http://www.google.com'
},{
title: 'Star Wars2!',
url: 'http://www.google.com'
},{
title: 'Star Wars3!',
url: 'http://www.google.com'
}
];
});
Also, don't forget that you need to specify in your view that there is a controller you want to use. For example, in your html:
<div ng-controller="MoviesCtrl">
<!-- any html you associate with your controller -->
</div>

AngularJS ng-repeat-start with limitTo doesn't work

I have a list of several objects and at the beginning I want to load just some of them. I took a look at the statement ng-repeat, but I need to have a structure like this:
<table class="table table-hover table-hidden">
<thead>
<tr>
...
</tr>
</thead>
<tbody>
<tr ng-repeat-start="object in objects | filter:query | orderBy:predicate:reverse" ng-init="isCollapsed=true">
...
</tr>
<tr ng-repeat-end class="more">
...
</tr>
</tbody>
</table>
I tried to apply the statement limitTo inside ng-repeat-start, in this way:
<tr ng-repeat-start="object in objects | filter:query | orderBy:predicate:reverse| limitTo: limit" ng-init="isCollapsed=true">
and on controller I wrote:
$scope.limit = 10;
$scope.incrementLimit = function () {
$scope.limit += 10;
};
The function incrementLimit is called by a click on hyperlink
<a href ng-click="incrementLimit()">more</a>
The list of objects is instantiated and filled (with all the elements) when the page loads.
With my approach at the beginnig are loaded and showed first 10 elements correctly, and when I click on "more" the variable $scope.limitis incremented, but on the page nothing happens. Anyone can explain me why?
limitTo is working fine inside ng-repeat-start
Take a look at this
var app = angular.module('myApp', []);
app.controller('Controller', function ($scope) {
$scope.limit = 1;
$scope.incrementLimit = function () {
$scope.limit += 1;
};
$scope.data = [{
title: 'Foo',
text: 'Lorem'
}, {
title: 'Bar',
text: 'Iste'
}, {
title: 'Jon',
text: 'Fat'
}, {
title: 'Los',
text: 'Ice'
}]
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.21/angular.min.js"></script>
<div ng-app='myApp' ng-controller="Controller">
<table border="2" class="table table-hover table-hidden">
<thead>
<tr>...</tr>
</thead>
<tbody>
<tr ng-repeat-start="object in data | filter:query | orderBy:predicate:reverse| limitTo: limit" ng-init="isCollapsed=true" ng-bind="object.title">...</tr>
<tr ng-repeat-end class="more">...</tr>
</tbody>
</table>
more
</div>
Please check the below code and fiddle it is working fine
<body ng-controller="myController">
<button ng-click="incrementLimit()" >increment</button> <br/>
<table class="table table-hover table-hidden">
<thead>
<tr clospan="3">
Head
</tr>
</thead>
<tbody>
<tr ng-repeat-start="friend in objects|limitTo: limit" ng-init="isCollapsed=true">
<td>{{friend.name}}</td>
<td>{{friend.phone}}</td>
<td>{{friend.age}}</td>
</tr>
<tr ng-repeat-end class="more">
<td colspan="3">Footer</td>
</tr>
</tbody>
</table>
</table>
</body>
js code
app = angular.module("app", []);
app.controller("myController", function($scope) {
$scope.objects =
[{
name: 'John',
phone: '555-1212',
age: 10
}, {
name: 'Mary',
phone: '555-9876',
age: 19
}, {
name: 'Mike',
phone: '555-4321',
age: 21
}, {
name: 'Adam',
phone: '555-5678',
age: 35
}, {
name: 'Julie',
phone: '555-8765',
age: 29
}];
$scope.limit = 2;
$scope.incrementLimit = function () {
$scope.limit += 1;
};
});
Fiddle http://jsbin.com/hoguxexuli/1/edit
I solved my problem. Basically I put the hyperlink in a different div, so the controller and the $scope were also different. It was a stupid carelessness.

Categories