ng-repeat inside ng-repeat creates empty td element - Angular - javascript

I've a little odd problem when using two ng-repeat for objects which contain arrays. Here is the Angular HTML-Code:
<tr data-ng-repeat="reqs in requirements | orderBy:['categoryOrder','order']">
<td>
<strong>{{reqs.category}}</strong>
</td>
<td data-ng-repeat="values in reqs.values | orderBy:'showOrder'">
<div data-ng-repeat="(key,value) in values">{{value}}</div>
<td>
</tr>
The table will be displayed fine and the data also looks fine. My only problem is, that after each tr an empy td element will be insert without any class and I can't get rid of it. Here is the outputted HTML:
<tr class="ng-scope" data-ng-repeat="reqs in requirements | orderBy:['categoryOrder','order']">
<td>
<strong class="ng-binding">Foobar</strong>
</td>
<td class="ng-scope" data-ng-repeat="values in reqs.values | orderBy:'showOrder'">
<td class="ng-scope" data-ng-repeat="values in reqs.values | orderBy:'showOrder'">
<td class="ng-scope" data-ng-repeat="values in reqs.values | orderBy:'showOrder'">
<td> </td>
</tr>
Does anyone else has experienced this kind of odd behaviour? The td element is completely empty and doesn't even has a class attribute assigned to it. Here is the object I'm using:
category: "Foobar"
categoryOrder: 10
description: "Some desc"
id: 2
order: 10
shortName: "SM-01"
values: [
0: {Foo: "Bar", showOrder: 1},
1: {Bar: "Foo", showOrder: 2},
2: {Meh: "Mah", showOrder: 3}
]
I'm using AngularJS 1.3.0. Any help is appreciated, as this is driving me nuts :).
Ares

missing closing tag <td> instead of </td>
don't worry.. we've all been there

You arent closing your td in your second td

Related

AngularJs seperate array and string in HTML template

I have a little problem with creating a dynamic HTML template. To display some data in a table, I have to separate between an ordinary String and an Array. First things first: The HTML template is included in another template using the data-ng-include directive with a controller. The controller contains my data which is essentially an object with different attributes. The objcect looks something like this and contains strings as well as arrays:
$scope.data = {
name: 'tony',
city: 'New York',
friends: ['Ann', 'Ben', 'John Doe'],
postal: 12345
};
There is also a matching array with the attributes to parse the information dynamically.
$scope.attributes = [{name: "Name", id: 'name'},
{name: "City", id: 'city'},
{name: "Friends", id: 'friends'},
{name: "Postal-code", id: 'postal'}
];
The data gets parsed inside the HTML using this code:
<table class="table table-striped">
<tbody>
<tr ng-repeat="attr in attributes">
<td>{{attr.name}}</td>
<td>{{data[attr.id]}}</td>
</tr>
</tbody>
</table>
This works absolutly fine for strings but I have to somehow determine if a attribute of data is an array to display the single records in a kind of List using ng-repeat on the record.
I tried to use Array.isArray(data[attr.id]) with an if-clause in different variations inside of <script>-tags but nothing works.
At the end the data of the friends-attribute should get displayed one below the other in the same cell like this:
Here is the code on JsFiddle
you can isArray but not directly inside ng-show.
you can use it like this.
$scope.isArray = angular.isArray;
so this way,
<tr ng-repeat="person in persons">
<td ng-repeat="attr in query.attribs">
<span ng-show="isArray(person[attr.id])">
<span ng-repeat="p in person[attr.id]">
{{p}}
</span>
</span>
<span ng-show="!isArray(person[attr.id])">
{{person[attr.id]}}
</span>
</td>
</tr>
Here is your updated Fiddle
You have to do some script and html changes if the value is an array like this Updated fiddle here : jsfiddle.net/Lt024p9h/7/
Do Something Like this.
<tr ng-repeat="person in persons">
<td ng-repeat="attr in query.attribs">
<span ng-show="isArray(person[attr.id])">
{{person[attr.id].toString()}}
</span>
<span ng-show="!isArray(person[attr.id])">
{{person[attr.id]}}
</span>
</td>
</tr>

AngularJS - Trouble with ng-repeat

Here's the data I'm working with:
$scope.products = [
{
'id': 643,
'name': 'Product Name',
'applications': [
{
'id': 100,
'name': 'Adobe After Effects CC (2014)',
'gfx': [
{
'id': 514,
'name': 'Graphics AE Test 1'
}
]
},
{
'id': 101,
'name': 'Adobe Premiere Pro CC (2014)',
'gfx': [
{
'id': 514,
'name': 'Graphics AP Test 1'
},
{
'id': 512,
'name': 'Graphics AP Test 2'
}
]
}
]
}
];
What i'm trying to do is loop through all of the graphics card for a specific application. You choose the application via a dropdown, and I have the selected application in a variable {{ scope.selectedApplication }}. So with that, here's what I have tried:
<tr data-ng-repeat="driver in result.applications | filter: { name: selectedApplication } track by $index">
<td>{{ driver.gfx[$index].name }}</td>
</tr>
So this is somewhat working, just not exactly how I want. The filter is filtering it down to the correct application, which works fine. The problem I am having is that driver.gfx[$index].name is only showing the first result. Since I am looping through applications instead of gfx, the $index isn't going to work for me.
How can I loop through the graphics cards after my initial ng-repeat? It seems like I need two statements, but how would that work?
Am I going about this the wrong way?
you can have nested hg-repeat if you like to have a nested table.
<tr data-ng-repeat="driver in result.applications | filter: { name: selectedApplication } track by $index">
<td>
<table>
<tr ng-repeat="item in driver.gfx">
<td >
{{item.name}}
<td/>
</tr>
</table>
</td>
</tr>
if you want to have single denormalized table, one option would be to create a function that does the denormalization and then use result of that function in a normal hg-repeat.
The other option would be having multiple tbody. so your outer loop occurs on tbody and inner loop on row
<tbody data-ng-repeat="driver in result.applications | filter: { name: selectedApplication } track by $index">
<tr ng-repeat="item in driver.gfx">
<td >
{{item.name}}
<td/>
</tr>
</tbody>
and finally you can have some rows that either style them as separators or just hide them by CSS and use ng-repeat-start and hg-repeat-end like this
<table>
<tr class="separator" data-ng-repeat-start="driver in result.applications | filter: { name: selectedApplication } track by $index"><td></td></tr>
<tr ng-repeat="item in driver.gfx">
<td >
{{item.name}}
<td/>
</tr>
<tr class="seperator" ng-repeat-end><td></td></tr>
</table>
You need another ng-repeat that loops through each gfx.
<td>
<ul>
<li ng-repeat="gfx in driver.gfx">{{ gfx.name }}</li>
</ul>
</td>
Assuming the selected application is set via a binding of {{ selectedApplication }} ($scope is implied), then your ng-repeat should look like:
<tr data-ng-repeat="driver in selectedApplication | filter: { name: selectedApplication } track by $index">
<td>{{ driver.gfx[$index].name }}</td>
</tr>
This means you'll be talking about the driver inside the selected application object.

AngularJS ng-repeat enable sorting on table columns

I am creating a table from a Array of JSONObject. And want to enable sorting on column header click. My code is as below.
<table>
<tr ng-repeat-start="record in records | orderBy:columnToOrder:reverse" ng-if="$first">
<td>S.No</td><td ng-repeat="(key,value) in record " ng-click="columnToOrder=key;reverse=!reverse">{{key}}</td>
</tr>
<tr ng-repeat-end >
<td>{{$index+1}}</td><td ng-repeat="(key,value) in record ">{{value}}</td>
</tr>
</table>
My data lookg like
[
{ Count="85923", Property Name="Name 1"},
{ Count="85933", Property Name="Name 2"},
{ Count="85953", Property Name="Name 3"},
{ Count="85973", Property Name="Name 4"}
]
But this code is not working. No error is shown too. Please help me enabling this functionality.
Instead of using the inline, define a method for ordering and use that method during click, since if the variables are defined in inline, the variables are created in the child scope and it would not be available for the parent ng-repeat-start scope.
Controller
$scope.order =function(key) {
$scope.columnToOrder=key;
$scope.reverse= !$scope.reverse
};
HTML
<table>
<tr ng-repeat-start="record in records | orderBy:columnToOrder:reverse" ng-if="$first">
<td>S.No</td><td ng-repeat="(key,value) in record " ng-click="order(key)">{{key}}</td>
</tr>
<tr ng-repeat-end>
<td>{{$index+1}}</td><td ng-repeat="(key,value) in record">{{value}}</td>
</tr>
</table>

Loop through array in array with Angular

Working on a TODO-app to learn Angular. I have this hardcoded array as a "database" and i want to display the tasks in the view.
var taskLists = [
{name: 'Todays todo', id: '1', tasks:['Make coffe', 'another task']},
{name: 'Tomorrow i will do this', id: '2', tasks:['Code well', 'go to bed']}
];
So how do i iterate through an array inside an array in an angular-view?
I tried to have two ng-repeats but cant get it to work right. I want to display the tasks one by one as <td>, not just the whole tasks array as one <td> as it does right now ['Make coffe', 'another task']
This is what the view looks like.
<h2 ng-repeat="object in list">{{object.name}}</h2>
<table>
<thead>
<tr>Tasks</tr>
</thead>
<tr>
<td ng-repeat="task in list">{{task.tasks}}</td>
</tr>
</table>
You have a problem in your logic.
Fist your HTML tag from child must be inside the parent.
<div class="parent" ng-repeat="object in list">
<h2>{{object.name}}</h2>
<table>
<thead>
<tr>Tasks</tr>
</thead>
<tr ng-repeat="task in object.tasks">
<td>{{item}}</td>
</tr>
</table>
</div>
Try this and check if it works.

ng-switch inside ng-repeat not working

I have data that basically boils down to this:
function ExampleCtrl($scope) {
$scope.myData= [
{text: "blah", other: 3, V: 'caseOne'},
{text: "blah", other: 3, V: 'caseTwo'},
{text: "blah", other: 3, V: 'caseThree'}
];
}
This is being used like this:
<div ng-controller="ExmapleCtrl">
<table>
<tr>
<td>Text</td>
<td>Other</td>
<td>V</td>
</tr>
<tr ng-repeat="data in myData">
<td>{{data.text}}</td>
<td>{{data.other}}</td>
<td ng-switch on="data.V">
<td ng-switch-when="caseOne"><img src="assets/img/pass.png"/></td>
<td ng-switch-when="caseTwo"><img src="assets/img/pass.png"/></td>
<td ng-switch-when="caseThree"><img src="assets/img/fail.png"/></td>
</td>
</table>
</div>
The problem is is that I am getting this error:
Error: No controller: ngSwitch..
I clearly have set the controller to ExampleCtrl, I don't see any typing errors, so I am at a loss unfortunately.
I believe the issue has to do with the ng-switch producing invalid markup. I'm not sure you can nest a td inside another td. Anyways, if you change it to this it will work:
<td ng-switch on="data.V">
<img src="assets/img/pass.png" ng-switch-when="caseOne"/>
<img src="assets/img/pass.png" ng-switch-when="caseTwo"/>
<img ng-switch-when="caseThree" src="assets/img/fail.png"/>
</td>
Here is a working demo: http://plnkr.co/edit/zUdkJYfnlJul6HsyCGfZ
I'll go ahead and suggest a couple more solutions that don't use a switch that might be a little nicer. Check out the last two td's
<tr ng-repeat="data in myData">
<td>{{data.text}}</td>
<td>{{data.other}}</td>
<td>
<img src='assets/img/{{data.V}}.png' /> <!-- assuming you have an image with name caseOne.png/caseTwo.png/etc -->
</td>
<td>
<img src='{{passFail[data.V]}}' /> <!-- transform the case stuff to pass/fail based on some business rules, this is an object but could be a function-->
</td>
</tr>
$scope.passFail = {
'caseOne' : 'assets/img/pass.png',
'caseTwo' : 'assets/img/pass.png',
'caseThree' : 'assets/img/fail.png'
};
An add-on to the above answer
Incase if there is just plain text inside td like switch casing user roles or something, you can add a span tag inside the td to contain the text
<td ng-switch="role">
<span ng-switch-when="1">Administrator</span>
<span ng-switch-when="2">Moderator</span>
</td>

Categories