How to update the number of columns in an angular table - angularjs

I want to change the number of columns on modifying a boolean variable.
Check my example (in plnkr):
angular.module('ui.bootstrap.demo', ['ngAnimate', 'ngSanitize', 'ui.bootstrap']);
angular.module('ui.bootstrap.demo').controller('myCtrl', function($scope, $log) {
$scope.debug = {};
$scope.fields = [{
header: "first",
hideField: !$scope.debug.flag
},
{
header: "second"
},
{
header: "third"
},
{
header: "fourth"
},
];
$scope.entries = [{
first: "hello1",
second: "hello2",
third: "hello3",
fourth: "hello4"
}, ]
$scope.myBool = true;
});
<!doctype html>
<html ng-app="ui.bootstrap.demo">
<head>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular-animate.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular-sanitize.js"></script>
<script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-2.5.0.js"></script>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div ng-controller="myCtrl">
<button id="testButton" class='btn btn-danger' ng-click='debug.flag = !debug.flag'><i class="glyphicon glyphicon-hand-right"></i> refreshFields! debug.flag = {{!!debug.flag}}</button>
<hr>
<h2 class="label label-info">table 1 with property.hideField = true</h2>
<table class="table table-hover">
<tr>
<!-- Headers of list-->
<th ng-repeat="property in fields" ng-if="!property.hideField">{{property.header}}
</th>
</tr>
<tbody>
<tr ng-repeat="entry in entries">
<td ng-repeat="property in fields" ng-if="!property.hideField">
{{entry[property.header]}} {{!!debug.flag}}
</td>
</tr>
</tbody>
</table>
<h4 class="label label-info">table 2 with ng-if => property.hideField = false</h4>
<table class="table table-hover">
<tr>
<!-- Headers of list-->
<th ng-repeat="property in fields" ng-if="property.hideField">{{property.header}}
</th>
</tr>
<tbody>
<tr ng-repeat="entry in entries">
<td ng-repeat="property in fields" ng-if="property.hideField">
{{entry[property.header]}} {{!!debug.flag}}
</td>
</tr>
</tbody>
</table>
<h2 class="label label-info">table 3 without ng-if</h2>
<table class="table table-hover">
<tr>
<!-- Headers of list-->
<th ng-repeat="property in fields">{{property.header}}
</th>
</tr>
<tbody>
<tr ng-repeat="entry in entries">
<td ng-repeat="property in fields">
{{entry[property.header]}} {{!!debug.flag}}
</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
How to reproduce it:
Click on the red button and the flag will toggle from false to true.
Expected behavior:
Table 1 starts with 3 columns. It should show four after clicking.
Table 2 starts with 1 column. It should show 0 columns after clicking.
Table 3 is just a control table with all the data.

Your heading would become visible if you modified the value of its hideField property. But you're not doing that. You're modifying the value of $scope.debug.flag.
The fact that hideField was initialized with the value of $scope.debug.flag won't magically change hideField every time you change $scope.debug.flag.
Just like if you do
var a = 1;
var b = a;
a = 42;
The value of b will still be 1. Not 42.

Changing the value of $scope.debug.flag won't change the value of hideField. Because, it has already been initialized at the time of controller load. The workaround you can apply here is bind that hideField to a method and evaluate that in your ng-if. Sample below.
JS:
$scope.fields = [{
header: "first",
hideField: function() {
return !$scope.debug.flag;
}
}, {
header: "second"
}, {
header: "third"
}, {
header: "fourth"
}, ];
HTML:
<h2 class="label label-info">table 1 with property.hideField = true</h2>
<table class="table table-hover">
<tr>
<!-- Headers of list-->
<th ng-repeat="property in fields" ng-if="!property.hideField()">{{property.header}}
</th>
</tr>
<tbody>
<tr ng-repeat="entry in entries">
<td ng-repeat="property in fields" ng-if="!property.hideField()">
{{entry[property.header]}} {{!!debug.flag}}
</td>
</tr>
</tbody>
</table>
This is not a clean solution though. But, still will solve your problem.

Related

Display complex json in Angularjs

I would like to display complex json with bollean values, strings and even with arrays. How can I do that?
$scope.options = {
"option_1" : "some string",
"option_2" : true,
"option_3" : [1.123456789, 0.123548912, -7.156248965],
"option_4" : null,
"option_5" : [1234.45678, 75.142012]
}
I use something like this : but I have problem with arrays :
<ul ng-repeat="(key, value) in options">
<li>{{key}}</li>
<span>{{value}}</span>
</ul>
I would like display something like table with keys like headings and values under appropriate keys like this :
option_1 option_2 option_3 ...
some string true 1.123456789
0.123548912
-7.156248965
It should be like this.
app = angular.module("myApp", []);
app.controller("myCtrl", function($scope) {
$scope.isArray = angular.isArray;
$scope.options = {
"option_1": "some string",
"option_2": true,
"option_3": [1.123456789, 0.123548912, -7.156248965],
"option_4": null,
"option_5": [1234.45678, 75.142012]
}
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="myCtrl">
<table class="table table-striped table-bordered table-hover">
<thead>
<tr>
<th ng-repeat="(key, value) in options">
{{ key }}
</th>
</tr>
</thead>
<tbody>
<tr>
<td ng-repeat="(key, value) in options">
{{isArray(value) ? '': value}}
<table ng-if="isArray(value)">
<tr ng-repeat="v in value">
<td>
{{v}}
</td>
</tr>
</table>
</td>
</tr>
</tbody>
</table>
</div>
</div>

Angular Data Table export to Excel using .withButtons:. Not able to see the buttons

I am trying to use angular datatables optionbuilder to create button for excel sheet download. But I am getting error withButton is not a function. I have downloaded all this files and have included in my main html page.
In HTML
<script src="/lib/angular-datatables.min.js"></script>
<script src="/lib/js_button/dataTables.buttons.min.js"></script>
<script src="/lib/js_button/buttons.flash.min.js"></script>
<script src="/lib/js_button/jszip.min.js"></script>
<script src="/lib/js_button/pdfmake.min.js"></script>
<script src="/lib/js_button/vfs_fonts.js"></script>
<script src="/lib/js_button/buttons.html5.min.js"></script>
<script src="/lib/js_button/buttons.print.min.js"></script>
<script src="/lib/angular-datatables.min.js"></script>
<link rel="stylesheet" type="text/css" href="/lib/js_button/buttons.dataTables.min.css">
In controller
var app = angular.module('myApp', ['Alertify','ngRoute', 'datatables']);
app.controller('MainCtrl', function($scope, $http, $location,
DTOptionsBuilder, DTColumnBuilder,Alertify) {..
$scope.vm.dtOptions = DTOptionsBuilder.newOptions()
.withOption('order', [])
.withOption('bFilter', false)
.withOption('bSort', false)
.withOption('bAutoWidth',true)
.withOption('sScrollY' , "200")
.withOption('sScrollX' , "100%")
.withOption('bScrollCollapse' , true)
.withPaginationType('full_numbers')
.withOption('lengthMenu', [5, 10, 25, 50, 100, 150, 200])
.withDOM('lrtip')
.withButtons([
{
extend: "excelHtml5",
filename: "MailItemList",
text: "<i class='fa fa-file-excel-o'></i> Excel",
title: "Mail Item List",
exportOptions: {
columns:[2,3,4,5,6,7,8.9,10,11,12,13,14,15,16,17,18,19,20,21,22]
},
exportData: { decodeEntities: true }
}
]);
..}
In Html
<table id="table1" class="table table-bordered table-hover fixed" datatable="ng" dt-columns="vm.dtColumns" dt-options="vm.dtOptions" >
<thead id="theadstyle">
<tr>
<th class="alignstyle"> </th>
<th class="alignstyle">1</th>
<th class="alignstyle">2</th>
<th class="alignstyle">3 </th>
<th class="alignstyle">4 </th>
<th class="alignstyle">5 </th>
<th class="alignstyle">6</th>
<th class="alignstyle">7 </th>
<th class="alignstyle">8</th>
</tr>
</thead>
<tbody >
<tr ng-repeat="build in buildmodel1">
<td> {{build.1}} </td>
<td> {{build.2}} </td>
<td> {{build.3}} </td>
<td> {{build.4}} </td>
<td> {{build.5}} </td>
<td> {{build.6}} </td>
<td> {{build.7}} </td>
<td> {{build.8}} </td>
</tr>
</tbody>
</table>
Can someone explain me what else needs to be added to this piece of code.
Adding B to dom, i.e .withDOM('Blrtip') will show buttons.
Error "withButtons is not a function" is because the js file dataTables.buttons.min.js is missing or , if you are in angular the module datatable.buttons is not defined
angular.module('app.components', [
...,'datatables.buttons']
Any remarks?

Angular js ng-repeat dynamic headers , avoid a column

On click of a button I get the following Response from Node JS .
[{
"_id": "590998cca8ac14d0c075282c",
"CompID": "0001388D",
"CompName": "ONE"
},
{
"_id": "590998cca8ac14d0c075282qc",
"CompID": "0001388D2",
"CompName": "TWO"
},
{
"_id": "590998cca8ac14d0c07528qq2c",
"CompID": "0001388D23",
"CompName": "Three"
}
]
I am printing this information using Angular JS table ng - repeat
This is my code
My question is , is it possible to skip _id field while printing ??
This is my code
<div ng-app="myapp" ng-controller="FirstCtrl">
<table border="1">
<tr>
<th ng-repeat="(key, val) in collectioninfo[0]">{{ key }}</th>
</tr>
<tr ng-repeat="row in collectioninfo">
<td ng-repeat="column in row">
{{ column }}
</td>
</tr>
</table>
</div>
JSFiddle
you can try with ng-if to avoid showing some elments in ng-repeat.
var myapp = angular.module('myapp', []);
myapp.controller('FirstCtrl', function($scope) {
$scope.collectioninfo = [{
"_id": "590998cca8ac14d0c075282c",
"CompID": "0001388D",
"CompName": "ONE"
},
{
"_id": "590998cca8ac14d0c075282qc",
"CompID": "0001388D2",
"CompName": "TWO"
},
{
"_id": "590998cca8ac14d0c07528qq2c",
"CompID": "0001388D23",
"CompName": "Three"
}
]
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<div ng-app="myapp" ng-controller="FirstCtrl">
<table border="1">
<tr>
<th ng-repeat="(key, val) in collectioninfo[0]" ng-if="key !== '_id'">{{ key }}</th>
</tr>
<tr ng-repeat="row in collectioninfo">
<td ng-repeat="(key2, val2) in row" ng-if="key2 !== '_id'">
{{ val2 }}
</td>
</tr>
</table>
</div>
Check the jsfiddle here
<table border="1">
<tr>
<th ng-repeat="(key, val) in collectioninfo[0]" ng-show="key != '_id'">{{ key }}</th>
</tr>
<tr ng-repeat="row in collectioninfo">
<td ng-repeat="column in row" ng-hide="column === row._id">
{{ column }}
</td>
</tr>
</table>
I have added a check for the key '_id'.
after you get the response in your angular controller do this :
$scope.datas = [];
//lines of code
.then(function success(response) {
$scope.collectionInfo=response.data.collectionInfo;
for(var i=0;i<$scope.collectionInfo.length;i++){
$scope.index=i;
$scope.datas.push($scope.collectionInfo[i]);
}
//lines of code
});
And on the html page do this :
<div id="DisplayCollection">
<table ng-repeat="x in collectionInfo">
<tr>
<th>
CompID
</th>
<th>
CompName
</th>
</tr>
<tr ng-repeat="y in x track by $index">
<td>{{y.compID[$index]}}</td>
<td>{{y.compName[$index]}}</td>
</tr>
</table>
Given that you have sent the data in form of an array: collectionInfo

how to have a popup child tr for every tr element on ng-click

I have a table which using ng-repeat
<table>
<thead>
<tr>
<th>Assets</th>
<th>Location</th>
<th>Size</th>
<th>Price</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr id="parent" data-ng-repeat="assets in vm.employees"
data-toggle="collapse" id="row{{$index}}" data-target=".row{{$index}}">
<td class="name">
<i class="mdi mdi-plus s16" ng-click="childRowToggle($event)"></i>
{{assets.name}}
<span class="secondary-text">{{assets.code}}</span>
</td>
<td>{{assets.location}}</td>
<td>{{assets.size}}</td>
<td>{{assets.price}}</td>
</tr>
<tr id="child" data-ng-repeat="assets in vm.employees" class="collapse row{{$index}}">
<div>i' have to be shown under every tr element when clicks
</tr>
</tbody>
</table>
If i click on the i element which is in parent tr, i want the child tr popup under that tr element. i already tried something like this
$scope.childRowToggle = function($event){
$('#childrow').remove();
var $this = $($event.target);
var $obj =$this.parent().parent();
console.log($obj.attr('class'));
$("<tr id='childrow'><td colspan='5'>Dummy Data</td></tr>").insertAfter($obj);
}
Here is a working version: https://jsfiddle.net/Shitsu/c6bj75mp/.
angular.module('myApp', []).controller('Ctrl',
function($scope) {
$scope.employees = [{
name: "lala",
location: "loc",
size: 10,
price: 44
}, {
name: "lala",
location: "loc",
size: 10,
price: 44
}, {
name: "lala",
location: "loc",
size: 10,
price: 44
}, {
name: "lala",
location: "loc",
size: 10,
price: 44
}, {
name: "lala",
location: "loc",
size: 10,
price: 44
}];
});
.noPadding {
padding: 0 !important;
}
td p {
padding: 10px;
margin: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="Ctrl">
<table class="table table-condensed" style="border-collapse:collapse;">
<thead>
<tr>
<th>Assets</th>
<th>Location</th>
<th>Size</th>
<th>Price</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr ng-repeat-start="assets in employees track by $index" data-toggle="collapse" data-target="#row-{{$index}}" class="accordion-toggle">
<td class="name">
<i class="mdi mdi-plus s16">{{assets.name}}</i>
<span class="secondary-text">{{assets.code}}</span>
</td>
<td>{{assets.location}}</td>
<td>{{assets.size}}</td>
<td>{{assets.price}}</td>
</tr>
<tr ng-repeat-end>
<td colspan="5" class="noPadding">
<div class="accordian-body collapse collapsible" id="row-{{$index}}">
<p>
Collapsed datas
</p>
</div>
</td>
</tr>
</tbody>
</table>
</div>
Have you thought of using tooltips ? UI-Bootstrap has really nice tooltips which would do exactly what you want. You can choose if you trigger the tooltip on hover or on click. Have a look at this fiddle.
HTML:
<!doctype html>
<html ng-app="App">
<body ng-controller="Ctrl">
<table>
<tr ng-repeat="a in assets">
<td tooltip-html-unsafe="{{a}}<br />blabla" tooltip-placement="bottom">{{a}}</td>
</tr>
</table>
</body>
</html>
JS:
angular.module('App', ['ui.bootstrap'])
.controller('Ctrl', function($scope) {
$scope.assets = ['a', 'b', 'c'];
});

angularjs ng-repeat show all list objects

I have this app which lets users create own events and others to register to those events. When creating event you can have as many questions as you like and you can name the questions as you wish. Those will be asked in the registration. App will fetch the names of the questions from the fields and record them in to the entries.
I am having problems to display a table of people that are going to attend. My app is handling one list:
var events = [{
Title: 'Summer Festival',
Date: '12.7.2015',
Location: 'Moon',
Description: Fillertxt,
url: "www.something.com",
MaxEntries: 10,
fields: [{
id: 'choice1',
name: "Gender"
}, {
id: 'choice1',
name: "Address"
}],
entries: []
},
Fields have all the questions and when I add an entry and print it it will show {"Gender":"rr","Address":"rr"} in this case.
The problem is that because I cannot foresee the names of those fields I cannot use ng-repeat and then just say <td>{{event.Gender}}<td>because it might as well be {{event.lifesmeaning}}. So how can i display a nice table with the registration info. Can I fetch those names from the fields somehow? I tried nested ng-repeat but didn't got it to work.
Here is also part of the registration page:
<div class="col-md-4">
<form>
<div class="border-box">
<center>
<h2 class="big">Participate:</h2>
<div data-ng-hide="!listFull()">The registration for this event is full.</div>
<div class="form-group" data-ng-hide="listFull()">
<label for="eventInput">Name</label>
<input style="width: 200px;" type="text" class="form-control" id="eventInput" data-ng-model="newEntry.name">
</div>
<div data-ng-repeat="field in event.fields" data-ng-hide="listFull()">
<div class="form-group">
<label for="{{$index + 1}}">{{field.name}}</label>
<input style="width: 200px;" type="text" class="form-control" id="{{$index + 1}}" data-ng-model="newEntry[field.name]">
</div>
</div>
<button style="width: 100px;" data-ng-click="addEntry()" class="btn btn-primary" data-ng-hide="listFull()">Save</button>
</center>
<br/>
</div>
</form>
<div class="border-box2">
<h2 class="big" align="center">Who is comming:</h2>
<p align="center">{{event.MaxEntries}} can participate.</p>
<table>
<tbody>
<tr data-ng-repeat="entry in event.entries">
<th>{{entry}}</th>
</tr>
</tbody>
</table>
<br/>
<br/>
</div>
</div>
If people are still stumbling upon this post...
1. Simple list of objects
So if you have a list/object of objects that will be populated dynamically, like such:
var list = [
{key1: 'value1'},
{key2: 'value2'}
]
And more key, value pairs will be added going forward (possibly with a push to the list).
In this case, the table body would be constructed as so
<tbody>
<tr ng-repeat="obj in sobjs">
<td ng-repeat="(key, value) in obj">
{{key}}
</td>
<td ng-repeat="(key, value) in obj">
{{value}}
</td>
</tr>
</tbody>
2. That was simple. Instead if you have a more complex structure as so:
var list = [
{'key1': [
{
'skey1':'sval11',
'skey2':'sval12'
},
{
'skey1': 'sval11a',
'skey2': 'sval11b'
}
]},
{'key2': [
{
'skey1':'sval21',
'skey2':'sval22'
},
{
'skey1': 'sval21a',
'skey2': 'sval21b'
}
]}
]
In this case the table body will be constructed as so:
<tbody>
<tr ng-repeat="obj in lobjs">
<td ng-repeat="(key, value) in obj">
{{key}}
</td>
<td ng-repeat="(key, value) in obj">
<table class="table table-bordered">
<thead>
<tr>
<th>
Sub-value 1
</th>
<th>
Sub-value 2
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="sobj in value">
<td>
{{sobj.skey1}}
</td>
<td>
{{sobj.skey2}}
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
Plunker working code: https://plnkr.co/edit/r4naGBaYAufhD073oXdw?p=preview
Code snippet with the same code below
function Ctrl($scope) {
$scope.sobjs = [{
'key1': 'value1'
}, {
'key2': 'value2'
}]
$scope.lobjs = [{
'key1': [{
'skey1': 'sval11',
'skey2': 'sval12'
}, {
'skey1': 'sval11a',
'skey2': 'sval11b'
}]
}, {
'key2': [{
'skey1': 'sval21',
'skey2': 'sval22'
}, {
'skey1': 'sval21a',
'skey2': 'sval21b'
}]
}]
}
<!DOCTYPE html>
<html ng-app="">
<head>
<link data-require="bootstrap-css#3.3.6" data-semver="3.3.6" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.css" />
<script data-require="angular.js#1.2.7" data-semver="1.2.7" src="https://code.angularjs.org/1.2.7/angular.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular.min.js"></script>
<script src="script.js"></script>
</head>
<body>
<div ng-controller="Ctrl">
<h2>Simple List of Objects</h2>
<table class="table table-bordered">
<thead>
<tr>
<th>
Key
</th>
<th>
Value
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="obj in sobjs">
<td ng-repeat="(key, value) in obj">
{{key}}
</td>
<td ng-repeat="(key, value) in obj">
{{value}}
</td>
</tr>
</tbody>
</table>
<h2>List of Objects with a list of objects as values for each key</h2>
<table class="table table-bordered">
<thead>
<tr>
<th>
Key
</th>
<th>
Value
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="obj in lobjs">
<td ng-repeat="(key, value) in obj">
{{key}}
</td>
<td ng-repeat="(key, value) in obj">
<table class="table table-bordered">
<thead>
<tr>
<th>
Sub-value 1
</th>
<th>
Sub-value 2
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="sobj in value">
<td>
{{sobj.skey1}}
</td>
<td>
{{sobj.skey2}}
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
Write an array of arrays and keep both field and value as element of array. Something like this :
var sample = [ [ sampleField, sampleValue ], [ anotherSampleField , anotherSampleValue ] ];
Now you can iterate using ng-repeat as :
<li ng-repeat = "index in sample"> index[0] : index[1]</li>

Resources