how to add a row to ngTable - angularjs

I am trying to add data from a typeahead selection to rows in a ngTable. I was using a regular bootstrap table for this but I needed to be able to edit the data after the row was added. INgTable has a table that can do this so I wanted to switch. I am not familiar with ngTable so any help would be great.
plunkr
//Add New POD Row
$scope.data = [];
$scope.addRow = function () {
$scope.data.push({
'JobItemName': $scope.masterItem.MLItemCode,
'JobItemDescription': $scope.masterItem.JobItemDescription,
});
$scope.masterItem.JobItemName = '';
$scope.masterItem.JobItemDescription = '';
};
//Remove POD Row
$scope.removeRow = function (JobItemName) {
var index = -1;
var comArr = eval($scope.data);
for (var i = 0; i < comArr.length; i++) {
if (comArr[i].JobItemName === JobItemName) {
index = i;
break;
}
}
if (index === -1) {
alert("Something gone wrong");
}
$scope.data.splice(index, 1);
};
$scope.tableParams = new ngTableParams({
page: 1, // show first page
count: 10 // count per page
}, {
total: $scope.data.length, // length of data
getData: function($defer, params) {
$defer.resolve($scope.data.slice((params.page() - 1) * params.count(), params.page() * params.count()));
}
});

Why use the ngTable directive and not something like this :
<table class="table table-striped table-hover">
<thead>
<tr>
<th>Column 1</th>
<th>Column 2</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in table" ng-click="editMyRow(row)">
<td ng-bind="row.column1"></td>
<td ng-bind="row.column2"></td>
</tr>
</tbody>
</table>
In this case, everytime you edit those values, your table will change in real time.
The controller would be something like :
angular.module('test').controller('blah', $scope){
$scope.table = {};
$scope.table.row = [];
$scope.table.row.add({
column1: '',
column2: ''
});
}

Related

AngularJS: Summing nested objects from multiple objects

Based in the following table I need to get the total of all subtotals.
I have tried to use the same sumByKey filter but I does't work.
Plus, the sum of all subtotals must be based on the result of the filter, it means, If we have two results (two categories) the sum of subtotals must be based on those objects. Any idea?
html
<table border="1">
<thead>
<tr>
<th>#</th>
<th>Category</th>
<th>Products with quantities</th>
<th>Subtotal of quantities</th>
</tr>
</thead>
<tbody align="center">
<tr data-ng-repeat="category in categories | filter:search">
<td>{{$index+1}}</td>
<td>{{category.name}}</td>
<td>{{category.products}}</td>
<td>{{category.products | sumByKey:'quantity'}}</td>
</tr>
</tbody>
<thead align="right">
<tr>
<td colspan="3"><strong>Total</strong></td>
<td></td>
</tr>
</thead>
</table>
angularjs
var app = angular.module("app", []);
app.controller("controllerApp", function($scope, $http){
$http.get("categories.json").success(function(data) {
$scope.categories = data;
});
});
app.filter('sumByKey', function () {
return function (data, key) {
if (typeof (data) === 'undefined' || typeof (key) === 'undefined') {
return 0;
}
var sum = 0;
for (var i = data.length - 1; i >= 0; i--) {
sum += parseInt(data[i][key]);
}
return sum;
}
});
May not be Angular solution. But you can also get total by pure JavaScript.
By keeping a total $scope varaible like this inside your controller
$scope.total = getTotal(data);
function getTotal(data){
var total = 0;
data.forEach(function(item){
item.products.forEach(function(product){
total += product.quantity;
})
});
return total;
}
Here is the updated Plunker.
It can be done with angular also.
Example : http://plnkr.co/edit/zhTtoOjW7J1oumktlvFP?p=preview
HTML:
<table border="1">
<thead>
<tr>
<th>#</th>
<th>Category</th>
<th>Products with quantities</th>
<th>Subtotal of quantities</th>
</tr>
</thead>
<tbody align="center">
<tr data-ng-repeat="category in filterValues=(categories | filter:search)">
<td>{{$index+1}}</td>
<td>{{category.name}}</td>
<td>{{category.products}}</td>
<td>{{category.products | sumByKey:'quantity'}}</td>
</tr>
</tbody>
<thead align="right">
<tr>
<td colspan="3"><strong>Total</strong></td>
<td>{{filterValues | sumOfValue:'quantity'}}</td>
</tr>
</thead>
</table>
JS:
// Code goes here
var app = angular.module("app", []);
app.controller("controllerApp", function($scope, $http) {
$http.get("categories.json").success(function(data) {
$scope.categories = data;
});
});
app.filter('sumByKey', function() {
return function(data, key) {
if (typeof(data) === 'undefined' || typeof(key) === 'undefined') {
return 0;
}
var sum = 0;
for (var i = data.length - 1; i >= 0; i--) {
sum += parseInt(data[i][key]);
}
return sum;
}
});
app.filter('sumOfValue', function() {
return function(data, key) {
if (angular.isUndefined(data) || angular.isUndefined(key)) {
return 0;
}
var sum = 0;
for (var i = 0; i < data.length; i++) {
var value = data[i];
if (!angular.isUndefined(value)) {
for (var j = 0; j < value.products.length; j++) {
sum += parseInt(value.products[j][key]);
}
}
}
return sum;
}
});

How to set a pre-selected option for ngTable select filter?

How to set a pre-selected option for ngTable select filter? My code is below and it is similar to the example from the official ngTable page. Now the selected value is an empty option and I want that the first option with a value is pre-selected by default (the one that is showing all the data in a table):
$scope.customersTable = new ngTableParams({
page: 1, // show first page
count: 10,
sorting: {
importDate: 'desc'
}
}, {
total: $scope.customers.length, // length of data
getData: function ($defer, params) {
var orderedData = params.sorting() ?
$filter('orderBy')($scope.customers, params.orderBy()) :
$scope.customers;
orderedData = params.filter ?
$filter('filter')(orderedData, params.filter()) :
orderedData;
$scope.custs = orderedData.slice((params.page() - 1) * params.count(), params.page() * params.count());
params.total(orderedData.length);
$defer.resolve($scope.custs);
}
});
var inArray = Array.prototype.indexOf ?
function (val, arr) {
return arr.indexOf(val)
} :
function (val, arr) {
var i = arr.length;
while (i--) {
if (arr[i] === val) return i;
}
return -1
};
$scope.importDates = function () {
var def = $q.defer(),
arr = [],
importDates = [];
$scope.$watch('customers', function () {
angular.forEach($scope.customers, function (item) {
if (inArray(item.importDate, arr) === -1) {
arr.push(item.importDate);
importDates.push({
'id': item.importDate,
'title': item.importDate
});
}
});
});
def2.resolve(importDates);
return def2;
};
And the HTML:
<table ng-table="customersTable" show-filter="true" class="table table-hover">
<tbody>
<tr data-ng-repeat="customer in $data">
<td data-title="'First Name'" sortable="'firstName'">
{{customer.firstName}}
</td>
<td data-title="'Import Date'" sortable="'importDate'" filter="{ 'importDate': 'select' }" filter-data="importDates()">
{{customer.importDate | date}}
</td>
</tr>
</tbody>
</table>
add filter property to your ngTableParams
$scope.customersTable = new ngTableParams({
page: 1, // show first page
count: 10,
sorting: {
importDate: 'desc'
},
filter:{importDate:'yourDefaultValue'},
.....})

Angular ng-table sorting not working in fixed header

I am very new to Angularjs. I have created an table using ng-table, The problem is the table header sorting is not working.
Sample code attached here.
HTML : (Sample ng-table)
<table ng-table="tableParams" show-filter="true" class="table">
<thead>
<tr>Row 1</tr>
<tr>Row 2</tr>
<tr>Row 3</tr>
<tr>Row 4</tr>
<tr>Row 5</tr>
<tr>Row 6</tr>
</thead>
<tbody>
<tr ng-repeat="user in $data">
<td sortable="'value1'">{{user.value1}}</td>
<td sortable="'value2'">{{user.value2}}</td>
<td sortable="'value3'">{{user.value3}}</td>
<td sortable="'value4'">{{user.value4}}</td>
<td sortable="'value5'">{{user.value5}}</td>
<td sortable="'value6'">{{user.value6}}</td>
</tr>
</tbody>
</table>
Controller :
$http.get('/portal/api/documents/'+Id).success(function(data){
var data = data.result;
$scope.tableParams = new ngTableParams({
page: 1, // show first page
count: 10, // count per page
sorting: {
name: 'asc' // initial sorting
}
}, {
total: data.length, // length of data
getData: function($defer, params) {
// Pagination
$defer.resolve(data.slice((params.page() - 1) * params.count(), params.page() * params.count()));
// use build-in angular filter
var orderedData = params.sorting ?
$filter('orderBy')(data, params.orderBy()) :
data;
$defer.resolve(orderedData.slice((params.page() - 1) * params.count(), params.page() * params.count()));
}
});
});
I think your problem comes from your sorting configuration :
sorting: {
name: 'asc' // initial sorting
}
You seem not to have a name parameter in one of your table column (value1, value2, ... unless you didn't show us your real code)
If you want to sort your first column, you should try this :
sorting: {
value1: 'asc' // initial sorting
}

Angular object property value change not propagated into view using ng-repeat

I'm trying to generate a table using ng-repeat.
Use case
The data to generate the table from looks as follows:
$scope.data = [
{
name : 'foo1',
group : 1
},
{
name : 'foo2',
group : 1
},
{
name : 'foo3',
group : 1
},
{
name : 'foo4',
group : 1
},
{
name : 'foobar',
group : 2
},
{
name : 'foobarbar',
group : 3
}
];
The html generated should look like this:
<tr>
<th>Group</th>
<th>Name</th>
</tr>
<tr>
<td rowspan="4">1</td>
<td>foo1</td>
</tr>
<tr>
<td>foo2</td>
</tr>
<tr>
<td>foo3</td>
</tr>
<tr>
<td>foo4</td>
</tr>
<tr>
<td rowspan="1">2</td>
<td>foobar</td>
</tr>
<tr>
<td rowspan="1">2</td>
<td>foobarbar</td>
</tr>
Implementation
I know the easiest way would probably be to pre-process the data and group the items per group in a new array of arrays. However, I chose a different approach:
<td
ng-if = "isDifferentFromPrev(items, $index, groupingData)"
rowspan = "{{item._groupSize}}"
>
with
$scope.isDifferentFromPrev = function(array, index, groupingData){
if(index === 0){
groupingData.startI = 0;
groupingData.counter = 1;
array[0]._groupSize = 1;
return true;
}
var eq = equalsMethod(array[index], array[index-1]);
if(eq){
groupingData.counter++;
array[groupingData.startI]._groupSize = groupingData.counter;
}
else{
groupingData.startI = index;
groupingData.counter = 1;
array[index]._groupSize = 1;
}
return !eq;
};
Problem
For some reason the rendered value for rowspan is always 1.
The attribute is only set for the first td of the first tr of a group, as intended, but the value for it is 1.
If I put a breakpoint inside isDifferentFromPrev(), the values seem to be updated correctly. This does not reflect in the html though.
Solution?
It occured to me that maybe ng-repeat renders each step sequentially, without returning to it. So maybe the _groupSize values for the first item of each group do get properly updated, but since they are updated after that item has already been rendered by ng-repeat, the update isn't processed anymore.
I have no idea if this reasoning is correct, nor about how to solve it. Any suggestions please?
This solution, even if a bit orthodox, does work:
var app = angular.module("myApp", []);
app.controller("myController", function($scope) {
$scope.data = [{
name: 'foo1',
group: 1
}, {
name: 'foo2',
group: 1
}, {
name: 'foo3',
group: 1
}, {
name: 'foo4',
group: 1
}, {
name: 'foobar',
group: 2
}, {
name: 'foobarbar',
group: 3
}];
$scope.itemHasRowspan = function(item) {
return typeof item === "object" && item.hasOwnProperty("rowspan");
};
var groupData = {},
currentGroup = null,
addGroup = function(firstItem) {
currentGroup = firstItem.group;
groupData[firstItem.group] = {
"firstItem": firstItem,
"count": 1
};
};
angular.forEach($scope.data, function(item, index) {
if (item.group !== currentGroup) {
addGroup(item);
} else {
groupData[item.group].count++;
}
});
angular.forEach(groupData, function(group, index) {
group.firstItem["rowspan"] = group.count;
});
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="myController">
<table>
<thead>
<tr>
<th>Group</th>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in data">
<td ng-if="itemHasRowspan(item)" rowspan="{{ item.rowspan }}" valign="top">
{{ item.group }}
</td>
<td>
{{ item.name }}
</td>
</tr>
</tbody>
</table>
</div>
</div>

Viewing datetime in ng-table?

I need ti display with ng-table in one column datetime:
var renderGrid = function(tableData) {
$scope.tableData = tableData;
if($scope.tableParams) {
$scope.tableParams.reload();
} else {
$scope.tableParams = new ngTableParams({
page: 1,
count: 10,
sorting: {
date: 'asc'
},
filter: {
date: ''
}
}, {
getData: function($defer, params) {
var sliceStart = (params.page() - 1) * params.count();
var sliceEnd = params.page() * params.count();
var orderedData = params.filter() ? $filter('filter')($scope.tableData, params.filter()) : $scope.tableData;
var filteredData = params.sorting() ? $filter('orderBy')(orderedData, params.orderBy()) : $scope.tableData;
$scope.totalCount = filteredData.length;
params.total(filteredData.length);
$defer.resolve(filteredData.slice(sliceStart, sliceEnd));
}
});
}
};
<table ng-table="tableParams" template-pagination="tcTableNav" class="tcTable">
<tr ng-repeat="item in $data">
<td style="width:34%" sortable="'date'" data-title="'Date'"><div>{{item.date}}</div></td>
<td style="width:33%" sortable="'autor'" data-title="'Autor'"><div>{{item.autor}}</div></td>
<td style="width:33%" sortable="'article'" data-title="'Article'"><div>{{item.article}}</div></td>
</tr>
</table>
How form datetime correctly that sorting + filtering work correctly?
i solved that by adding a textfield with the formatted date to my tableData
Did you try using instead ngTasty table http://zizzamia.com/ng-tasty/directive/table ,
and if you want you can just upload an example of the structure you want sort and I will write you the complete solution :)

Resources