AngularJS recursive templates using tables - angularjs

I am trying to work out how to do recursion using table tags with angularjs. I have the following data structure
$scope.report = [{
'Name': 'Moo',
'Value': 'MooV',
'Children': [{
'Name': 'Moo2',
'Value': 'Moo2V',
'Children': [{
'Name': 'Moo3',
'Value': 'Moo3V'
}]
}]
}];
The recursion can have no limit. I am looking to put in a simple table with the format
<table>
<tr>
<td>Moo</td>
<td>MooV</td>
</tr>
<tr>
<td>Moo2</td>
<td>Moo2V</td>
</tr>
<tr>
<td>Moo3</td>
<td>Moo3v</td>
</tr>
<table>
but I am unable to get it working just right. This will allow me to do certain things to the sections while looking flat to the user. Currently I have the code
<div ng-app="app" ng-controller='AppCtrl'>
<script type="text/ng-template" id="rloop">
<td>{{data.Name}}</td>
<td>{{data.Value}}</td>
<tr ng-repeat="data in data.Children" ng-include src="'rloop'"></tr>
</script>
<table class="table table-condensed">
<thead>
<tr>
<th>Name</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr ng-repeat-start="data in report" ng-include="'rloop'"></tr>
<tr ng-repeat-end></tr>
</tbody>
</table>
</div>
but this is not going to work due to in repeating it creates a tr tag within a tr tag. I have tried various different methods of moving the repeat to tbody etc etc but I can't seems to get it working due to the restrictions of tables in HTML. Example, is not allowed within tr.
JSFiddle showing issue here: JSfiddle

As you say, this is not going to work within the table. Maybe it would be better to recursively convert the data to an array of Name/Value pairs, then use those in the normal way?
var app = angular.module('app', []);
function includeChildren([first, ...rest]) {
if (!first) return [];
const {Name, Value, Children = []} = first;
return [{Name, Value}, ...includeChildren(Children), ...includeChildren(rest)];
}
app.controller('AppCtrl', function ($scope) {
$scope.report = [{
'Name': 'Moo',
'Value': 'MooV',
'Children': [{
'Name': 'Moo2',
'Value': 'Moo2V',
'Children': [{
'Name': 'Moo3',
'Value': 'Moo3V'
}]
}]
}];
$scope.reportTable = includeChildren($scope.report);
// $scope.reportTable now contains:
// [{Name: 'Moo', Value: 'MooV'}, {Name: 'Moo2', Value: 'Moo2V'}, {Name: 'Moo3', Value: 'Moo3V'}]
});
Now you can use a more unsurprising template:
<div ng-app="app" ng-controller='AppCtrl'>
<table class="table table-condensed">
<thead>
<tr>
<th>Name</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="data in reportTable">
<td>{{data.Name}}</td>
<td>{{data.Value}}</td>
</tr>
</tbody>
</table>
</div>
See it working here: https://jsfiddle.net/k6rf9g1p/1/

Related

ng-click, ng-model not working in angularjs datatable

I have a datatable with column filters made with AngularJS.
Here is the HTML:
<body ng-app="myApp" ng-controller="appController as Ctrl">
<table class="table table-bordered table-striped table-hover dataTable js-exportable" datatable="ng" dt-options="Ctrl.dtOptions" dt-columns="Ctrl.dtColumns">
<thead>
<tr>
<th></th>
<th>Name</th>
</tr>
</thead>
<tfoot>
<tr>
<th></th>
<th>Name</th>
</tr>
</tfoot>
<tbody>
<tr ng-repeat="user in userList">
<td>
<input type="checkbox" id="user-{{ $index }}" ng-model="Ctrl.checkboxValue[$index]" ng-click="Ctrl.checkValue(user.id)" ng-true-value="{{user.id}}" />
<label for="user-{{ $index }}"></label>
</td>
<td>
<a href="#">
{{ ::user.name }}
</a>
</td>
</tr>
</tbody>
</table>
Here's the script:
angular.module('myApp', ['ngAnimate', 'ngSanitize', 'datatables', 'datatables.columnfilter'])
.controller('appController', function($scope, $compile, DTOptionsBuilder, DTColumnBuilder){
$scope.userList = [
{
id: '1',
name: 'hello'
},
{
id: '2',
name: 'hi'
}
];
var vm = this;
vm.dtOptions = DTOptionsBuilder.newOptions()
.withPaginationType('full_numbers')
.withOption('createdRow', function (row, data, dataIndex) {
$compile(angular.element(row).contents())($scope);
})
.withColumnFilter({
aoColumns: [{
}, {
type: 'text',
bRegex: true,
bSmart: true
}]
});
vm.dtColumns = [
DTColumnBuilder.newColumn('').withTitle(''),
DTColumnBuilder.newColumn('name').withTitle('Name'),
];
vm.checkboxValue = [];
vm.checkValue = function(id){
console.log(id);
}
});
Issues:
id of the user does not get passed to checkValue function. Hence, the console.log is undefined.
Suppose if the checkbox of 1st user is checked, the value of checkboxValue array is [undefined: '1']. If checkbox of 2nd user is checked the value of checkboxValue array becomes [undefined: '2'].
Only one checkbox gets checked. Why is that?
Demo: https://plnkr.co/edit/A3PJfBuwtpUQFAIz8hW7?p=preview
You kill your code with redundancy. Look at this :
When using the angular way, you CANNOT use the dt-column directive.
Indeed, the module will render the datatable after the promise is
resolved. So for DataTables, it's like rendering a static table.
You are in fact using the "angular way" along with dt-columns. You could switch to use DTColumnDefBuilder but why define the columns when you already have a <thead> section? It would only make sense if you need to use sorting plugins etc on specific columns. And / or not is specifying the header in the markup.
Moreover, when you are rendering with angular it is not necessary to $compile anything, in fact is is very wrong, angular already does that. So
remove your dt-columns or replace it with a dt-column-defs literal
remove your $compile from the createdRow callback
Then it works. I would also remove the ng-true-value="{{user.id}}" attribute. You want an array representing the checkboxes state, why set the state to the user.id and not true or false?
vm.dtOptions = DTOptionsBuilder.newOptions()
.withPaginationType('full_numbers')
.withColumnFilter({
aoColumns: [{
}, {
type: 'text',
bRegex: true,
bSmart: true
}]
});
and
<input type="checkbox" id="user-{{ $index }}" ng-model="Ctrl.checkboxValue[user.id]" ng-click="Ctrl.checkValue(user.id)" />
Is really all you need.
forked plunkr -> https://plnkr.co/edit/Z82oHi0m9Uj37LcdUSEW?p=preview

Angular-js ng-if issue in tables TD

I'm trying to hide a td, when getting a value = 0,
I typed
<table>
<tr ng-repeat="row in typeData"
<td ng-if="row.AMOUNTPAID > 0">#{{row.AMOUNTPAID}}</td>
</tr>
</table>
The td is not hiding, I tried ng-show it works but ng-show works on the css, and an empty space still showing in the table with the td border.
I read about updating angular-js will fix the problem, i have 1.4.6 it has the ngif directive but not working.
Any help please ?
Hard to see how your data object is defined, please find a possible solution beneath. I've made a sample, provided with some dummy data.
Also see the JSFiddle
The problem in your example is that the tr close tag is missing at :
<tr ng-repeat="row in typeData"
VIEW
<div ng-app="myApp">
<div ng-controller="testCtrl">
<table>
<tr ng-repeat="row in data">
<td>{{row.name}}</td>
<td ng-if="row.amountpaid > 0">{{row.amountpaid}}</td>
<td ng-if="row.amountpaid <= 0">NO PAYMENT YET</td>
</tr>
</table>
</div>
</div>
CONTROLLER
var myApp = angular.module('myApp', []);
// controller
myApp.controller("testCtrl", function($scope) {
// set data
$scope.data = [{
'name': 'bot1',
'amountpaid': '145'
}, {
'name': 'bot2',
'amountpaid': '10'
}, {
'name': 'bot3',
'amountpaid': '5'
}, {
'name': 'bot4',
'amountpaid': '0'
}, {
'name': 'bot5',
'amountpaid': '0'
}];
})

AngularJS access another array with $index under ng-repeat

I new to AngularJS and wish to access two arrays under ng-repeat. This is my code:
<tr ng-repreat="find in findOptions">
<td>find.first</td>
<td>find.second</td>
<td>{{ search[{{$index}}].third }}</td>
</tr>
search is another array that I want to access here
You can't have iterpolation inside a intepolation again, basically you could access scope variable directly inside it.
You could simply directly use $index to access array.
search[$index].third
Created JSFiddle Demonstration - https://jsfiddle.net/qtksp1kj/
Hope this will help!
<body ng-app="SampleApp">
<table ng-controller="fcController" border="1px">
<thead>
<tr>
<td>Name</td>
<td>Address</td>
<td>LandMark</td>
</tr>
</thead>
<tbody ng-repeat="element in myArray">
<tr>
<td>{{element.name}}</td>
<td>{{element.address}}</td>
<td>{{myArray1[$index].landMark}}</td>
</tr>
</tbody>
</table>
</body>
var sampleApp = angular.module("SampleApp", []);
sampleApp.controller('fcController', function($scope) {
$scope.myArray = [{
'name': 'Name1',
'address': 'H-1 China Town'
}, {
'name': 'Name2',
'address': 'H-2 China Town'
}];
$scope.myArray1 = [{
'landMark': 'Near Dominos'
}, {
'landMark': 'Near Airport'
}];
});

angular angular-table dynamic header name

I use angular and angular-table to display multiple tables on the same page.
I need to create dynamic table with dynamic header and dynamic content.
Plunkr her
This is a working example with non dynamic header but I don't find how to make dynamic
The controller :
angular.module('plunker', ['ui.bootstrap',"angular-table","angular-tabs"]);
function ListCtrl($scope, $dialog) {
$scope.cols= ['index','name','email'];
$scope.list = [
{ index: 1, name: "Kristin Hill", email: "kristin#hill.com" },
{ index: 2, name: "Valerie Francis", email: "valerie#francis.com" },
...
];
$scope.config = {
itemsPerPage: 5,
fillLastPage: true
};
}
HTML
<!-- this work -->
<table class="table table-striped" at-table at-paginated at-list="list" at-config="config">
<thead></thead>
<tbody>
<tr>
<td at-implicit at-sortable at-attribute="name"></td>
<td at-implicit at-sortable at-attribute="name"></td>
<td at-implicit at-sortable at-attribute="email"></td>
</tr>
</tbody>
</table>
<!-- this fail ... -->
<table class="table table-striped" at-table at-paginated at-list="list" at-config="config">
<thead></thead>
<tbody>
<tr>
<td ng-repeat='col in cols' at-implicit at-sortable at-attribute="{{col}}"></td>
</tr>
</tbody>
</table>
I am missing some think or it is not possible with this module ?
Did you know another module where you can have dynamic header and pagination ? ( i try also ngTable but have some bug issu with data not being displayed )
Through the below code, you can generate dynamic header
<table class="table table-hover table-striped">
<tbody>
<tr class="accordion-toggle tblHeader">
<th ng-repeat="(key, val) in columns">{{key}}</th>
</tr>
<tr ng-repeat="row in rows">
<td ng-if="!$last" ng-repeat="col in key(row)" ng-init="val=row[col]">
{{val}}
</td>
</tr>
</tbody>
</table>
Angular Script
var app = angular.module('myApp', []);
app.controller('myControl', function ($scope, $http) {
$http.get('http://jsonplaceholder.typicode.com/todos').success(function (data) {
$scope.columns = data[0];
$scope.rows = data;
}).error(function (data, status) {
});
$scope.key = function (obj) {
if (!obj) return [];
return Object.keys(obj);
}
});

Sorting only certain arrays in nested ngRepeat

I currently have a nested ngRepeat, where the inner loop iterates over a collection of items from its parent. An excerpt:
<div ng-repeat="person in persons">
(Irrelevant code here.)
<table>
<tr>
<th ng-click="setItemOrder('name')">Item name</th>
<th ng-click="setItemOrder('number')">Item number</th>
</tr>
<tr ng-repeat="item in person.items | orderBy:itemOrder">
<td>{{item.name}}
<td>{{item.number}}
</tr>
</table>
</div>
By clicking the table headers, I set the itemOrder-property in my controller to the name of the property I want orderBy to use:
$scope.setItemOrder = function(order){
$scope.itemOrder = order;
}
This all works fine, except that if I click the headers in one person-div, the item-tables in all person-divs get sorted on that property.
Is there a way to make ngRepeat only apply orderBy to entries that match a certain criteria - for instance a certain index? Or should I use a different approach?
Try setting the property to respective person instance as follows:
angular.module('test', []).controller('testController', function($scope) {
$scope.persons = [{
items: [{
name: 'test',
number: 2
}, {
name: 'test1',
number: 1
}]
}, {
items: [{
name: 'test3',
number: 5
}, {
name: 'test4',
number: 4
}]
}];
$scope.setItemOrder = function(person, order) {
person.itemOrder = order;
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<form ng-app="test" ng-controller="testController">
<div ng-repeat="person in persons">
<table>
<tr>
<th ng-click="setItemOrder(person,'name')">Item name</th>
<th ng-click="setItemOrder(person,'number')">Item number</th>
</tr>
<tr ng-repeat="item in person.items | orderBy:person.itemOrder">
<td>{{item.name}}
<td>{{item.number}}
</tr>
</table>
</div>
You could add a ordering variable for each person and extend setItemOrder with the person object. Then you can call:
setItemOrder(person, 'name');
and then use it in the ngRepeat:
orderBy:person.itemOrder
angular.module('test', []).controller('testController', function($scope) {
$scope.ordersort=true;
$scope.orderfield='number';
$scope.persons = {
"items": [{
"name": 'test',
"number": 2
}, {
"name": 'test1',
"number": 1
}],
"item1": [{
"name": 'test3',
"number": 5
}, {
"name": 'test4',
"number": 4
}]
};
$scope.setItemOrder = function(person, order) {
$scope.orderfield=order;
person.itemOrder = order;
$scope.ordersort= !$scope.ordersort;
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<form ng-app="test" ng-controller="testController">
<div ng-repeat="person in persons">
<table>
<tr>
<th ng-click="setItemOrder(person,'name')">Item name</th>
<th ng-click="setItemOrder(person,'number')">Item number</th>
</tr>
<tr ng-repeat="item in person | orderBy:orderfield:ordersort">
<td>{{item.name}}
<td>{{item.number}}
</tr>
</table>
</div>
I have modified your example. In this example table sorting is working perfectly. But It is not sorted the particular table when I click on that table header. Anyway to sort columns by specific table?
angular.module('test', []).controller('testController', function($scope) {
$scope.persons = [{
items: [{
name: 'test',
number: 2
}, {
name: 'test1',
number: 1
}]
}, {
items: [{
name: 'test3',
number: 5
}, {
name: 'test4',
number: 4
}]
}];
$scope.setItemOrder = function(person, order) {
person.itemOrder = order;
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<form ng-app="test" ng-controller="testController">
<div ng-repeat="person in persons">
<table>
<tr>
<th ng-click="setItemOrder(person,'name')">Item name</th>
<th ng-click="setItemOrder(person,'number')">Item number</th>
</tr>
<tr ng-repeat="item in person.items | orderBy:person.itemOrder">
<td>{{item.name}}
<td>{{item.number}}
</tr>
</table>
</div>

Resources