AngularJS dynamic table with multiple headers based on hierarchical collections - angularjs

I'm trying to create a table with two rows for header, based on a hierarchical collection. I've found that ng-repeat can't do that, and I'm trying to make the job with a directive and Angular.forEach.
Here the jsfiddle : http://jsfiddle.net/echterpat/RxR2M/9/
But my problem is that when I made the first display of table, collections were empty (they were filled by REST call afterward), so link method was not able to build all the table. And then when REST updated collections, link method was not called anymore...
Any idea to call directive after REST answer, and to fill my table with collected data ?
Directive with angular.forEach :
myApp.directive('myTable', ['$compile', function (compile) {
var linker = function (scope, element, attrs) {
var html = '<table BORDER="1"><thead>';
html += '<tr><th><button type="submit" class="btn btn-info">Back</button></th>';
angular.forEach(scope.myFirstCol, function (item, index) {
html += '<th colspan="{{item.mySecondCol.length}}" id="item_{{item.id}}"> {{item.name}}</th>';
});
html += '</tr><tr><th><input type="checkbox" ng-model="selectAll"/></th>';
angular.forEach(scope.myFirstCol, function (item2, index) {
angular.forEach(item2.mySecondCol, function (item3, index) {
html += '<th id="headerStep_{{item3.id}}">{{item3.name}}</th>';
});
});
html += '</tr></thead>';
html += '</table>';
element.replaceWith(html);
compile(element.contents())(scope);
};
return {
restrict: 'E',
rep1ace: true,
link: linker,
scope: {
myFirstCol: '=myFirstCol'
}
};
}]);

If you dont want to use a directive, you can go for nested tables:
<table BORDER="1">
<thead>
<tr>
<th>
<button type="submit" class="btn btn-info">Back</button>
</th>
<th ng-repeat="item in myFirstCol">{{item.name}}</th>
</tr>
<tr>
<th>
<input type="checkbox" ng-model="selectAll" />
</th>
<th ng-repeat="item in myFirstCol">
<table BORDER="1">
<tr>
<th ng-repeat="item2 in item.mySecondCol">
{{item2.name}}
</th>
</tr>
</table>
</th>
</tr>
</thead>
</table>

Related

AngularJS ordering collection

I have a simple inbox table which consists of mails that have mailtext, sender and date attributes. I want this table to be sortable in terms of every one of these attributes when clicked to correspondent table header. Right now I am only trying to order this table in terms of sender attribute. I am using AngularJS 'orderBy' filter but nothing changes in the table. What is wrong with my code?
HTML Code Snippet:
<div class="container">
<h2>Your Inbox</h2><br><br>
<table ng-show="showInboxTable" class="table table-hover">
<thead>
<tr>
<th>Mail</th>
<th ng-click="sortMailsSender()">Sender</th>
<th>Date</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="mail in mails">
<td>{{mail.mailtext}}</td>
<td>{{mail.sender}}</td>
<td>{{mail.date}}</td>
</tr>
</tbody>
</table>
</div>
AngularJS Controller:
$scope.sortMailsSender = function()
{
if ( !$window.sessionStorage.inboxCompare || $window.sessionStorage.inboxCompare == 'gt')
{
console.log('filter straight');
$filter('orderBy')($scope.mails, 'sender', false);
$window.sessionStorage.setItem('inboxCompare', 'lt');
}
else
{
console.log('filter reverse');
$filter('orderBy')($scope.mails, 'sender', true);
$window.sessionStorage.setItem('inboxCompare', 'gt');
}
}
You should assign to your $scope.mails after applying filter and syntax should be
$scope.mails = $filter('orderBy')($scope.mails , 'sender', false);

How to get visible row of table in Angular JS after doing filtration

I am showing list on table using html (table, tr, td) and angularJS. Table also contains filters on columns. Table is populating data properly and filters are working properly using AngularJS.
After doing some filtration, I want to get only visible rows in one of my angularJS's function.
How can I get only the Visible Rows of a Table in angularJS after Few Filters?
Please note that I am not using any checkboxes or radio buttons with data list.
Please see my code below:
var myapp=angular.module("myapp",[]);
myapp.controller('ctrcommodity',['$scope',function($scope) {
$scope.commodity={
allPreferredCommodity: [
{
"commodityId": "2016070011220000141",
"commodityName": "Computer (PC)"
},
{
"commodityId": "2016080011220000004",
"commodityName": "Laptop"
},
{
"commodityId": "2016070011220000032",
"commodityName": "Keyboard"
},
{
"commodityId": "2016080011220000054",
"commodityName": "Mouser"
}
]
};
$scope.getVisibleRows=function()
{
//want to get details of visible rows after filtration
}
}]);
<table border="1" cellpadding="0" cellspacing="0">
<thead>
<tr>
<th>Commodity Id</th>
<th>Commodity Name</th>
</tr>
</thead>
<tbody>
<tr>
<td><input type="text" name="txtcid" id="txtcid" ng-model="s.commodityId"></td>
<td><input type="text" name="txtcname" id="txtcname" ng-model="s.commodityName"></td>
</tr>
<tr ng-repeat="commoditylist in commodity.allPreferredCommodity | filter:s">
<td>{{commoditylist.commodityId}}</td>
<td>{{commoditylist.commodityName}}</td>
</tr>
<tr>
<td align="center" colspan="6" height="50">
<input type="button" value="Show Visible Rows" ng-click="getVisibleRows()">
</td>
</tr>
</tbody>
Do like the follwing . I am changing your function as
$scope.getVisibleRows=function(arrayData,s)
{
console.log(s);
$scope.filerList=$filter('filter')(arrayData,s);
alert( $scope.filerList);
//want to get details of visible rows after filtration
}
and similarly change it is html also like ng-click="getVisibleRows(commodity.allPreferredCommodity,s)"
dont forget to inject filter to controller like myapp.controller('ctrcommodity',['$scope','$filter',function($scope,$filter)

Angular loop through table row and check for checked checbox

I have a table that has a list from database with checkbox on each row, checkbox will used for ex. during deletion of the record.
So what i am trying to achieve is that when i clicked the delete button, angular will loop each row in table and check the checkbox whether is checked, if yes the please proceed to delete. Dont have any idea how to do this. Someone please give some related example.
Here is my code
index.html
<button class="ui red labeled icon button right floated" type="button" data-content="Delete selected item(s)" id="delete" ng-click="deleteSeleted()"><i class="trash icon"></i>Delete</button>
<div class='container-table'>
<table class="ui fixed single line celled table striped sortable compact" style="width:2000px" id="mytable">
<thead>
<tr>
<th class="width-checkbox"><input type="checkbox" ng-model="matin.selectedAll" /></th>
<th class="width-120">Item</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="x in data">
<td><input type="checkbox" ng-checked="matin.selectedAll"></td>
<td>{{x.item}}</td>
</tr>
</tbody>
</table>
</div>
<tr ng-repeat="x in data">
<td><input type="checkbox" ng-model="x.selected"></td>
<td>{{x.item}}</td>
</tr>
Angular Js Code
for (var k = 0; k < $scope.data.length; k++)
{
if($scope.data[k].selected==true)
{
//Perform your desired thing over here
var val=$scope.data[k].item //to getData
}
}
Please find the fiddler link which i have created to select all the items in the table and on delete print which ever is checked https://jsfiddle.net/dfL1L944/3/
var appModule = angular.module('Module', []);
appModule.controller("DataController", function($scope) {
$scope.data = [{"name":"Alex"},{"name":"Juni"}]
$scope.deleteAll = false;
$scope.deleteSeleted = function(){
$scope.data.forEach(function(x) {
console.log(x.name);
});
}
$scope.selectedAll = function(){
$scope.data.forEach(function(x) {
if($scope.deleteAll){
x.deleted = true;
}
else{
x.deleted = false;
}
});
}
});
HTML Code
<div ng-app="Module"> <div ng-controller="DataController">
<button class="ui red labeled icon button right floated" type="button" data-content="Delete selected item(s)" id="delete" ng-click="deleteSeleted()"> <i class="trash icon"></i>Delete</button> <div class='container-table'> <table class="ui fixed single line celled table striped sortable compact" style="width:200px" id="mytable"> <thead>
<tr>
<th width="20px">
<input type="checkbox" ng-model="deleteAll" ng-click="selectedAll()" /></th>
<th>Item</th>
</tr> </thead> <tbody>
<tr ng-repeat="x in data">
<td width="2px"><input type="checkbox" ng-checked="x.deleted"></td>
<td>{{x.name}}</td>
</tr> </tbody> </table> </div>
</div> </div>
You could use $filter (you would need to insert $filter as a dependency)
$scope.data: [ // assuming your model looks like this
{
Id: "my_id",
Name: "my_name",
checked: true
}
];
var myFilteredValues = $filter('filter')($scope.data, { $: true });
And in your HTML
<tr ng-repeat="x in data">
<td><input type="checkbox" ng-model="x.checked"></td>
<td>{{x.Name}}</td>
</tr>
You can add a .toDelete property to every x in your data array, for example, and bind the checkboxes like this:
<input type="checkbox" ng-model="x.toDelete">
Afterwards you can create a button under the table:
<input type="button" ng-click="deleteRows();" value="Delete rows">
...And then create a function on your controller's scope (a newbie-friendly function):
$scope.deleteRows = function(){
var i=0;
for(i=0; i<data.length; i++){
if(data[i].toDelete){
//send your server requests here and do
//your stuff with the element if needed
data.splice(i, 1); //remove the element from the array
i--; //decrement the value of i so it stays the same
//(array is now shorter than it used to be)
}
}
}
You can also keep the information on what row is to be deleted in a separate array on the same scope but this solution seems simpler to me.
Regarding the "Check All" checkbox at the top, you can create a function and bind it with ng-click to a button or any other element and use that function to simply iterate through all the elements and set the .toDelete property to true for each one of them.

Populate and update a table with data from a different table

My site allows for a user to search for a term which returns a table of associated songs. When the "Add Track" button in a particular row is clicked after the search, the respective track name and trackId are added to the table "playlist". The problem I am having is that once "Add Track" is clicked within a different row, the data from that row is not added to the "playlist" table, but rather it just replaces the previous information. I need to be able to generate a cumulative table. Any help would be great and thanks in advance!
<body ng-app>
<body ng-app>
<div ng-controller="iTunesController">
{{ error }}
<form name="search" ng-submit="searchiTunes(artist)">
<input type="search" required placeholder="Artist or Song" ng-model="artist"/>
<input type="submit" value="Search"/>
</form>
<div class="element"></div>
<table id="SongInfo" ng-show="songs">
<thead>
<tr>
<th>Album Artwork</th>
<th>Track</th>
<th></th>
<th>Track Id</th>
<th>Preview</th>
<th>Track Info</th>
<th>Track Price</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="song in songs">
<td><img ng-src="{{song.artworkUrl60}}"
alt="{{song.collectionName}}"/>
</td>
<td>{{song.trackName}}</td>
<td><button ng-click="handleAdd(song)">Add Track</button></td>
<td>{{song.trackId}}</td>
<td>Play</td>
<td>View Track Info</td>
<td>{{song.trackPrice}}</td>
</tr>
</tbody>
</table>
<table id="playlist">
<thead>
<tr>
<th>Playlist</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="song in addedtracks">
<td>{{song.trackName}}</td>
<td>{{song.trackId}}</td>
</tr>
</tbody>
</table>
</div>
</body>
itunes_controller.js
var iTunesController = function($scope, $http){
$scope.searchiTunes = function(artist){
$http.jsonp('http://itunes.apple.com/search', {
params: {
'callback': 'JSON_CALLBACK',
'term': artist,
limit: 5,
}
}).then(onSearchComplete, onError)
}
$scope.handleAdd = function(song) {
// this song object has all the data you need
console.log("handle add ", song)
$scope.addedtracks = [{song:'trackName', song:'trackID'}]
$scope.addedtracks.push(song)
}
var onSearchComplete = function(response){
$scope.data = response.data
$scope.songs = response.data.results
}
var onError = function(reason){
$scope.error = reason
}
}
I saw some issues with your code. First the code below
$scope.addedtracks = [{song:'trackName', song:'trackID'}]
$scope.addedtracks.push(song)
Acording to your html, you are passing the song object to the handleAdd. So just remove the first line from code above. After that step, declare addedtracks array before handleAdd like below
$scope.addedtracks = [];
Modify the ng-repeat for the playlist like below:
<tr ng-repeat="song in addedtracks track by $index">
<td>{{song.trackName}}</td>
<td>{{song.trackId}}</td>
</tr>
And that's it. Note that I used track by $index because ngRepeat does not allow duplicate items in arrays. For more information read Tracking and Duplicates section.
Finally this is working plunker

What is angular way to transform a table cell

The problem is as follows. I have a directive which builds some table, and i use ng-repeat to construct table rows dynamicly. Each row has two buttons for editing and deleting accordingly. I look for action with ng-click, but how then transform a cell with static text into a cell with an input field in angular way? I know how to do it with jquery. I look around with ng-switch, but i can't get it works inside ng-repeat on a table cell as expected. My code:
JS
order.directive('orderLines',function($http,calculateTotalQtyService,$compile){
return {
restrict: 'A',
link: function($scope,element, attrs){
$scope.editLine = function(line,order_id){
// alert ('Edit'+line.id);
some code here to perform transformation
}
$scope.deleteLine = function(idx){
var line_to_delete = $scope.order.lines[idx]
$http.post('/delete/line?id='+line_to_delete.id +'&order_id='+$scope.order.id).success(function(data){
$scope.order.lines.splice(idx,1);
$scope.order = data.ord;
$scope.order.customer = data.customer;
$scope.order.lines = data.lines;
var res = calculateTotalQtyService.set(data.lines);
$scope.total_kg = res[0];
$scope.total_piece = res[1];
});
}
},
templateUrl:'/assets/fragments/order/order_lines.html',
replace: true
}
});
and HTML
<div class="span12 fiche" id="lines">
<table class="table table-bordered" id="order_lines">
<thead class="header_lines">
<th>S.N.</th>
<th>Ref.</th>
<th>Label</th>
<th>Tva</th>
<th>Qty</th>
<th>Unite</th>
<th>Prix HT</th>
<th>Total HT</th>
<th></th>
</thead>
<tbody ng-switch="lines.length">
<tr id="no_record" ng-switch-when="0"><th colspan="9" style="text-align: center" >No records</th></tr>
<tr ng-repeat="line in order.lines">
<td>{{$index+1}}</td>
<td class='line-ref'>{{line.product_ref}}</td>
<td>{{line.label}}</td>
<td class='line-tva'>{{line.tva}}</td>
<td class='line-qty'>{{line.qty}}</td>
<td class='line-unity'>{{line.unity}}</td>
<td class='line-prix_ht'>{{line.prix_ht}}</td>
<td>{{line.prix_ht*line.qty}}</td>
<th class='control-buttons'>
<button class='btn editline' ng-click="editLine(line,order.id)"><i class='icon-edit'></i></button>
<button class='btn deleteline' ng-click="deleteLine($index)"><i class='icon-trash'></i> </button>
</th>
</tr>
</tbody>
</table>
</div>
So html is a template, that i use in directive. How perform transformation ? with ng-switch? but how, or there are other solutions ? I want to avoid jquery if it's possible. Any help would be appreciated.
So I got it with a custom directive, inspired by #laut3rry. For those who would be interested this is my solution:
Directive:
order.directive('editable', function(){
return {
restrict : 'E',
replace : true,
template: '<div><span ng-hide="editMode">{{line.qty}</span><input class="span1" ng-show="editMode" type="text" ng-model="line.qty"/></div>',
link : function(scope, element, attrs){
}
}
});
And in HTML, in my example it's for a qty cell only, that I need to change, but we can use it with any cell and with a little bit of modification, for example by passing cell value in the attribute of the directive and it can be universal:
<td class='line-qty'><editable></editable></td>
In my controller I initialize $scope.editMode = false the cell isn't editable by default and then in the ng-click="editLine()" handler we change $scope.editMode = true and the cell transforms in to the input field. So directives and directives and once more directives.... :)
For those who is interested, here the link to the plunk plunk

Resources