Ng-repeat within an ng-repeat-start - javascript

My data:
$scope.members = [
{
projects: [...]
},
{
projects: [...]
}, ...
] // $scope.members.length == 15
My code:
<tr>
<th ng-repeat-start="member in members" ng-repeat="project in member.projects" ng-repeat-end ng-if="member.projects" >
{{project.name}}
</th >
</tr>
No element is generated. I checked the Elements in Chrome developer tool, and I found these in the <tr> tag comments like this:
<!-- ngRepeat: member in members -->
<!-- ngRepeat: member in members -->
<!-- end ngRepeat: member in members --> (x30)
I also tried this:
<tr ng-repeat-start="member in members">
<th ng-repeat="project in member.projects" ng-repeat-end ng-if="member.projects" >
{{project.name}}
</th >
</tr>
But then I have the error: Unterminated attribute, found 'ng-repeat-start' but no matching 'ng-repeat-end' found.
Does anyone have an idea? Thanks in advance.

Updated answer:
Get only the 'projects' arrays into a new array, like so:
$scope.projectsOnly = [];//empty array
$scope.members.forEach(function(item){
$scope.projectsOnly.push(item.projects);
})
and then loop only into that array, like so:
<tr>
<th ng-repeat="project in projectsOnly " >
{{project.name}}
</th >
</tr>
Hope helps, good luck.

You should simply do this with nested ng-repeat
<tr ng-repeat="member in members">
<th ng-repeat="project in member.projects" ng-if="member.projects">
{{project.get('name')}}
</th>
</tr>

you don't need the ng-if, and you shouldn't separate the ng-repeat start/end. Just use two ng-repeats, one inside the other:
<div ng-app="app">
<table ng-controller="TestController">
<tr ng-repeat="member in members">
<th ng-repeat="project in member.projects">
{{project.name}}
</th>
</tr>
</table>
</div>
and your controller can look like this:
var app = angular.module('app', []);
app.controller('TestController', function($scope) {
$scope.members = [{
projects: [{
name: '1'
}, {
name: '2'
}]
}, {
projects: [{
name: '3'
}, {
name: '4'
}]
}];
});

Related

How to bind an object to HTML table in Vue.js, where its properties are dynamically created?

I am using vue.js library for front-end development.
I came a cross a scenario where my JavaScript method returns a list, which has objects, object's number of properties can change each time after method execution.
example my list can contain these type of objects in 2 different executions.
var obj = {
Name : "John",
2020-Jan: 1,
2020-Jul: 2
}var obj = {
Name: "John",
2020-Jan: 1,
2020-Jul: 2,
2021-Jan: 3,
2021-Jul: 4
}
Since Property name is dynamically changes is there any way to bind to HTML ?
<div >
<table>
<thead>
<tr>
<th v-for ="row in Result.Headers">
{{row}}
</th>
</tr>
</thead>
<tbody>
<tr v-for="item in Result.Data ">
<td>
{{item.2020-Jan}} // Because don't know the number of properties until run time
</td> // No of <td/>'s can change on no of properties.
<td> // exactly don't know how many <td>'s needed there.
{{item.2020-Jul}}
</td> <td>
{{item.2021-Jan}}
</td>
</tr>
</tbody>
</table>
</div>
Is there way to bind these type of object to fronted in vue.js ?
You need to loop over the item's keys again. This will show all the values in the object
<tbody>
<tr v-for="item in Result.Data ">
<td v-for="(value, key, index) in item">
{{value}}
</td>
</tr>
</tbody>
If you want to filter some of them, for instance check that the keys are valid dates you need to add a v-if and use Date.parse to check for this.
<tbody>
<tr v-for="item in Result.Data ">
<td v-for="(value, key, index) in item" v-if="Date.parse(key) !== NaN">
{{value}}
</td>
</tr>
</tbody>
if u wana show all attr-> u can use this:
<ul v-for="item in Result ">
<li v-for="(value,key,index) in item">{{value}}</li>
</ul>
if u wana show all days u can use v-if and compute to complete youself fillter
<div id="app">
<ul v-for="item in Result" >
<li v-for="(value,key,index) in item" v-if="canShow(key)"> index:{{index}}------ key: {{key}} ------ value:{{value}} </li>
</ul>
</div>
<script>
var vue=new Vue({
el:'#app',
data:{
Result:[{
name: 'SkyManss',
2020-Jan: 1,
2020-Jul: 2
},{
name: 'SkyManss2',
2020-Jan: 1,
2020-Jul: 2,
2021-Jan: 3,
2021-Jul: 4
}]
},
computed:{
canShow(){
return function(skey){
return skey.indexOf('-') > -1;
}
}
}
});
</script>
after some research and some of your suggestions I came up with an answer.
<div>
<table>
<thead>
<tr>
<th v-for ="row in Result.Headers">
{{row}}
</th>
</tr>
</thead>
<tbody>
<tr v-for="item in Result.Data ">
<td v-for="row in Result.Headers">
{{item[row]}}
</td>
</tr>
</tbody>
</table>
</div>
Javascript code
this.Result.Headers = Object.keys(result.data[0]);
this.Result.Data = result.data;
But this code only worked for the first time. second time data didn't get updated. So I updated JavaScript code to following code.
Vue.set(self.Result, 'Headers', []);
Vue.set(self.Result, 'Result', []);
this.Result.Headers = Object.keys(result.data[0]);
this.Result.Data = result.data;
Vue does not allow dynamically adding new root-level reactive properties to an already created instance. That I got to know from following post.
vue.js is not updating the DOM after updating the array
Thank You All !!!

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 count items in nested ng-repeat without $index

I want to count iteration of ng-repeat, when condition match.
I've tried $index but it print for all itration/items in nested ng-repeat
Fiddle link :https://jsfiddle.net/gdr7p1zj/1/
<tbody ng-controller="MainCtrl">
<tr ng-repeat-start="a in test1">
<td>{{a.categoryName}}(count_here)</td>
</tr>
<tr ng-repeat-end ng-repeat="b in test" ng-if="a.categoryId==b.categoryId">
<td>{{b.name}}</td>
</tr>
</tbody>
i want like this
category_one(4) <=item count 4 items in this category so 4 will display
item1
item2
item3
item4
category_two(2)
item5
item6
<!-- this is in controller -->
$scope.test1=[{
categoryId:'1',categoryName:'category one'
},
{
categoryId:'2',categoryName:'category two'
}]
$scope.test = [
{categoryId:'1',name:'cate 1 elem0'},
{categoryId:'1',name:'cate 1 elem1'},
{categoryId:'2',name:'cate 2 elem'}
];
});
An option is to create a function (getCount) in the controller which do the count, something like this:
$scope.getCount = function(categoryId) { // returns the count by matching by categoryId
return $scope.test.filter(function(element) { // first, filter elements in `test`
return element.categoryId === categoryId; // matching by categoryId
}).length; // then, return the count of how many results we got after the filter
}
And in the html call that function like this:
<tbody ng-controller="MainCtrl">
<tr ng-repeat-start="a in test1">
<td>{{a.categoryName }} ({{getCount(a.categoryId)}})</td> <!-- <-- call the function in order to display the count -->
</tr>
<tr ng-repeat-end ng-repeat="b in test" ng-if="a.categoryId == b.categoryId">
<td>{{b.name}}</td>
</tr>
</tbody>
See a demo here: https://jsfiddle.net/lealceldeiro/v9gj1ok4/11/
Thanks for your help. But i get expected output without any functions call or filters
Here fiddle Link: https://jsfiddle.net/wk3nzj96/
htmlCode:
<div ng-app='myapp' >
<div ng-controller="MainCtrl">
<table ng-init="$scope.counter=0">
<tr ng-repeat-start="cate in mainCategory">
<td> {{cate.name}} ({{$scope.counter[$index]}})</td></tr>
<tr ng-repeat="itemsItr in items" ng-init="$scope.counter[$parent.$parent.$index]=$scope.counter[$parent.$parent.$index]+1" ng-if="itemsItr.mid==cate.id">
<td>{{itemsItr.name}}</td>
</tr>
<tr ng-repeat-end ng-if="false"></tr>
</table>
</div>
</div>
and ControllerCode:
(function() {
angular.module('myapp', []).controller('MainCtrl', function($scope) {
$scope.mainCategory = [
{ name: "categoryOne",id:1 },
{ name: "categoryTwo",id:2 }
];
$scope.items = [
{ name: "item1FromCateOne" ,mid:1 },
{ name: "item2FromCateOne",mid:1 },
{ name: "item3FromCateOne" ,mid:1 },
{ name: "item1FromCateTwo",mid:2 }
];
});
Is this Standard way to do this?

Display Object in HTML table ng-repeat - Angular

My Object looks like this
Object
207T : Object
metal : 1
steel : 2
205T : Object
metal : 1
steel : 3
208T : Object
metal : 1
steel : 3
209T : Object
metal : 0
steel : 9
Now this object i need to display in below format
207T, 205T, 208T, 209T should be in table heading which is fine
<tr>
<th></th>
<th></th>
<th ng-repeat="(key, value) in mainObj">{{key}}</th>
</tr>
And then the format should be
How to acheive this
We can not create table column wise so in this case best and cleanest way would be to filter out the row values and using them inside view. So
In controller
app.controller(['$scope', function($scope){
$scope.object= values;
$scope.valuesMetal= [];
$scope.valuessteel = [];
// initializing row values for use in the using in view
angular.forEach(values, function(value, key) {
$scope.valuesMetal.push(value.metal );
$scope.valuessteel.push(value.metal );
});
}]);
In the view we just display our values
<tr>
<th ng-repeat="(key, value) in mainObj">{{key}}</th>
</tr>
<tr>
<td >Metal</td>
<td ng-repeat="(key, value) in valuesMetal" >{{value}}</td>
</tr>
<tr>
<td >steel</td>
<td ng-repeat="(key, value) in valuessteel" >{{value}}</td>
</tr>
<div>
For the header you need to convert the object to array:
// inside controller
mainObjArray = Object.keys(mainObj); // ['207T', '205T', '208T', '209T']
// header html
<tr>
<th ng-repeat="key in mainObjArray">{{key}}</th>
</tr>
And for the rest of values you can do some like:
// inside controller
mainObjValues = mainObjArray.map(function(item){
return mainObj[item];
}); // output: [{metal: 1, steel: 2}, {...}]
Then the body-table:
<tbody>
<tr ng-repeat="item in mainObjValues">
<td>{{item.metal}}</td>
<td>{{item.steel}}</td>
....
</tr>
</tbody>
angular.module("app",[])
.controller("ctrl",function($scope){
var sampleObj = {
"207T":{
"metal":1,
"steel":2
},
"205T":{
"metal":1,
"steel":3
},
"208T":{
"metal":1,
"steel":3
},
"209T":{
"metal":0,
"steel":9
}
}
$scope.metal = [];
$scope.steel= []
$scope.keys = Object.keys(sampleObj);
angular.forEach(sampleObj, function(obj) {
$scope.metal.push(obj.metal );
$scope.steel.push(obj.steel );
});
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<table>
<tr>
<th ng-repeat="item in keys">{{item}}</th>
</tr>
<tr>
<td >Metal</td>
<td ng-repeat="item in metal track by $index" >{{item}}</td>
</tr>
<tr>
<td >Steel</td>
<td ng-repeat="item in steel track by $index" >{{item}}</td>
</tr>
</table>
</div>
This is actually simple.
<table>
<tr>
<th></th>
<th ng-repeat="(key, value) in mainObj">{{key}}</th>
</tr>
Here you are ng repeating in th, will display 207t, 205T etc
<tr ng-repeat="item in items track by $index">
<td ng-repeat="item1 in item track by $index">{{item[$index]}}</td>
</tr>
Here you have to ng repeat tr, so that it will display metal and steel. and then each td u have to ng repeat and should display with index item[$index]

Filtering an array by number in AngularJS

I'm wondering if I can do something like the code below in AngularJS. The goal is to filter the array by all ids >= the search id. Can I do the search inline or does it have to be done as a custom filter in javascript?
<div style="margin-top:5px;margin-left:30px;">
<div>
<div>ID</div>
<span class="glyphicon glyphicon-search"></span>
<input type="text" ng-model="listFoodItems.searchid" />
</div>
<table class="table table-responsive">
<thead>
<tr>
<th>ID</th>
<th>Description</th>
<th>Discount</th>
</tr>
</thead>
<tfoot></tfoot>
<tbody>
<tr ng-repeat="row in listFoodItems.fullitemdescs | filter: EntryId >= searchid">
<td>{{row.EntryId}}</td>
<td>{{row.ItemDesc}}</td>
<td>{{row.ItemDisc}}</td>
</tr>
</tbody>
</table>
</div>
Best way make a custom filter like:
HTML
<div ng-app>
<div ng-controller="MyCtrl">
<input type="text" ng-model="searchid" />
<ul>
<li ng-repeat="person in people | filter:myFilter">
{{person.id}}
-
{{person.name}}
</li>
</ul>
</div>
</div>
JS
function MyCtrl($scope){
$scope.people = [
{id: 1, name: "Mark"},
{id: 2, name: "John"},
{id:3, name: "Joe"}
];
$scope.myFilter = function(item){
if(item.id >= $scope.searchid){
return item;
}
};
}
here its my fiddle with example: https://jsfiddle.net/javierif/mmoo3s8m/
First, create a function
$scope.lessThan = function(prop, val){
return function(item){
return item[prop] < val;
}
}
Next, in your ng-repeat
<tr ng-repeat="row in listFoodItems.fullitemdescs | filter: lessThan('EntryId', searchid)">
Original answer here:
https://stackoverflow.com/a/24081564/5141584

Categories