ng-table grouping - initialize with rows minimised - angularjs

I am using the grouping example of ng-table from http://plnkr.co/edit/CBcbkc
Right now the table is initialised with rows expanded, but I would like them to be minimised as I have over 100 records. How can I do this?

You can set group.$hideRows to true using ngInit:
<tbody ng-repeat="group in $groups" ng-init="group.$hideRows = true">
Update
I wanted to find a better solution, because the angular docs discourage using ngInit to access scope variables.
You can create a controller for each group created in the ng-repeat:
<tbody ng-repeat="group in $groups" ng-controller="groupCtrl">
Then, you can access the group object directly. One advantage of this would be the ability to conditionally expand a group:
.controller('groupCtrl', function($scope) {
if ($scope.group.value != 'Administrator')
$scope.group.$hideRows = true;
});
http://plnkr.co/gXfsBq
FYI
I wondered why I couldn't find any references to $hideRows in the source. It turns out that the group object doesn't have a $hideRows property until after it is clicked. To prove this, I replaced $hideRows with a made up name and it worked just the same.
<tbody ng-repeat="group in $groups">
<tr class="ng-table-group">
<td colspan="{{$columns.length}}">
<a href="" ng-click="group.invokeInvisbility = !group.invokeInvisbility">
<span class="glyphicon" ng-class="{ 'glyphicon-chevron-right': group.invokeInvisbility, 'glyphicon-chevron-down': !group.invokeInvisbility }"></span>
<strong>{{ group.value }}</strong>
</a>
</td>
</tr>
<tr ng-hide="group.invokeInvisbility" ng-repeat="user in group.data">
No wonder you couldn't find a way to initialize it.

You can tell ngTable to not expand it via the property 'groupOptions' see below:
var table = new NgTableParams({ group: 'name' }, { dataset: users, groupOptions: { isExpanded: false } });

Just add groupOptions: {isExpanded:false} in the params section.
Below is a copy of your code with the proper add-on.
$scope.tableParams = new ngTableParams({
page: 1, // show first page
count: 10, // count per page
groupOptions: {isExpanded:false}
}, {
groupBy: 'role',
total: data.length,
getData: function($defer, params) {
var orderedData = params.sorting() ?
$filter('orderBy')(data, $scope.tableParams.orderBy()) :
data;
$defer.resolve(orderedData.slice((params.page() - 1) * params.count(), params.page() * params.count()));
}
});

Related

Output is concatenated

New click on [Filter] does not clear previous output but adding to exists.
For example, if filtered by "banned" I see the banned users list, next filter by "registered" does not remove the "banned" but adding the "registered" to the end of the table.
In controller $scope.site_users overwritten, but somewhere it still saves the previous filter output.
Why is that happens? May be something on packages side?
Installed packages:
urigo:angular - Angular
angularui:angular-ui-router
accounts-password
accounts-ui
twbs:bootstrap
Removed packages:
insecure
autopublish
Or in code
Controller:
angular.module("sis_admin_am").controller("UsersListCtrl", ['$scope', '$meteor',
function($scope, $meteor){
$scope.filter = function(){
$scope.site_users = '';
$scope.site_users = $meteor.collection(Users).subscribe('site_users_filtered', {status: $scope.userStatus});
};
}
]);
View:
<form ng-submit="filter()">
<button>Filter</button>
<select ng-model="userStatus" >
<option ng-selected="selected">banned</option>
<option>registered</option>
<option>active</option>
</select>
</form>
<p></p>
<table class="table">
<tr class="panel panel-default">
<th>Name</th>
<th>Email</th>
</tr>
<tr ng-repeat="user in site_users">
<td>{{ user.username }}</td>
<td>{{ user.email }}</td>
</tr>
</table>
Server part:
Meteor.publish('site_users_filtered', function(options) {
console.log('options:', options);
return Users.find(options);
});
That's because how Subscriptions in Meteor works.
If you add or change a subscription without closing the ones before, it will just add them all together (which is good but you have to be aware of it).
If you want to filter with subscriptions (for security reasons) you should change your code like that:
angular.module("sis_admin_am").controller("UsersListCtrl", ['$scope', '$meteor',
function($scope, $meteor){
var savedSubscriptionHandle = null;
$scope.filter = function(){
savedSubscriptionHandle.stop();
$scope.site_users = '';
$scope.site_users = $meteor.collection(Users);
$scope.$meteorSubscribe('site_users_filtered', {status: $scope.userStatus}).then(function(handle){
savedSubscriptionHandle = handle;
});
};
}
]);
But if you don't mind keeping all the data in the local cache it might be easier to use Angular's filters or Meteor's cursor syntax to filter the display.
More detailed explanation here:
http://angular-meteor.com/tutorial/step_12
I think your problem is, ngSelected NOT necessarly select only one choice of your dropdown.
and that is because,tchnically you should de-select your unwanted userStatus manually as they do in the official doc :
https://docs.angularjs.org/api/ng/directive/ngSelected
You can try to send your ng-model (userState) along to the filter() function and actually filter with that value directly without having to check the scope.

ng-table data not showing on page load

I have integrated ngTable into my mean.io stack and I'm having trouble with populating the table on page load. If I select one of the column headers, the data shows up and the table works as advertised.
Here is my html
<table ng-table="tableParams" class="table">
<tbody ng-repeat="p in $data">
<tr id="tr{{p._id}}" ng-class-odd="'odd'" ng-class-even="'even'">
<td class="rowTd" data-title="'Task Code'" sortable="'task_code'">{{p.task_code}}</td>
<td class="rowTd" data-title="'Task Name'" sortable="'task_name'">{{p.task_name}}</td>
<td class="rowTd" ><input type=button id="editRowBtn{{p._id}}" value="edit"
ng-click="setEditId(p._id)"></td>
</tr>
<tr ng-show="editId===p._id" ng-if="editId===p._id">
<td colspan="7" ng-include src="'editRow.html'"></td>
</tr>
</tbody>
</table>
Here is my controller code.
var data = GeneralTasks.query();
$scope.tableParams = new ngTableParams({
page: 1,
count: 10
},{
total: data.length,
getData: function($defer, params) {
params.total(data.length);
$defer.resolve(data.slice((params.page() - 1) * params.count(), params.page() * params.count()));
}
});
$scope.editId = -1;
$scope.setEditId = function(pid) {
$scope.editId = pid;
};
I am new to using this table so i'm sure there is something i'm overlooking.
Wanted to provide the answer to my question so it may help others. Anytime an item in the table is added or removed, the table must be reloaded. Since $save and $remove invoke a callback function, just inserted the following for updating the table.
$scope.add = function() {
if (!$scope.tasks) $scope.tasks = [];
var task = new GeneralTasks({
task_code: $scope.task_code,
trade: $scope.trade,
task: $scope.task,
task_name: $scope.task_name
});
task.$save(function(response) {
$scope.tasks.push(response);
var data = $scope.tasks;
$scope.tableParams.total(data.length);
$scope.tableParams.reload();
});
this.task_code = this.trade = this.task = this.task_name = '';
};
First i update the $scope list with the response and then update the tables data and length. Then just call reload.
As I've stated earlier, i do this for $save and $remove. Here is the $remove code.
$scope.remove = function(task) {
for (var i in $scope.tasks) {
if ($scope.tasks[i] === task) {
$scope.tasks.splice(i, 1);
}
}
task.$remove();
var data = $scope.tasks;
$scope.tableParams.total(data.length);
$scope.tableParams.reload();
};
I have noticed that when I edit a name in the list and then cancel, the name does not reset. I suppose I should add similar code for the cancel action but I'm lazy and that's the least of my worries for now. :)
Hope this helps someone else.

How to dynamically re-draw data in table. Angular ngTable

I have controller with just 1 function getList(). When I call it first time - everything is just fine and my table show proper data. But when I call this function again (with new params in order to get different data in response), I still have data in table from the first call. How to reload/redraw/refresh data?
module.controller("IPsCtrl", function($scope, $filter, IPService, ngTableParams) {
$scope.data_out = {
'ip_pattern' : '%',
};
$scope.getList = function() {
$scope.data=IPService.getList($scope.data_out,
function(response) {
$scope.tableParams = new ngTableParams({
page: 1, // show first page
count: 10, // count per page
filter: {
id: '' // initial filter
},
sorting: {
id: 'asc' // initial sorting
}
}, {
total: response.list.length, // length of data
getData: function($defer, params) {
// use build-in angular filter
var filteredData = params.filter() ?
$filter('filter')(response.list, params.filter()) :
response.list;
var orderedData = params.sorting() ?
$filter('orderBy')(filteredData, params.orderBy()) :
response.list;
params.total(orderedData.length); // set total for recalc pagination
$defer.resolve(orderedData.slice((params.page() - 1) * params.count(), params.page() * params.count()));
}
});
});
};
});
Here is html view
<table ng-table="tableParams" show-filter="true" class="table">
<tr ng-repeat="user in $data">
<td data-title="'Name'" sortable="'id'" filter="{ 'id': 'text' }">
{{user.id}}
</td>
<td data-title="'Age'" sortable="'value'" filter="{ 'value': 'text' }">
{{user.value}}
</td>
</tr>
</table>
There is a provided method to do just that:
$scope.tableParams.reload();
Just call it after you update the data the table is displaying.
Edit:
First off, I think your current use of ngTable is incorrect. Instead of tying the table directly to the response data, I think the best thing to do would be to store your response data in a $scope variable, and then attach it to your ngTable. That way you only have to manipulate the $scope data and call reload.
From there it is simply a matter of updating the stored data then calling reload:
// Store your data in a dedicated variable
$scope.myData = response.list;
// Update ngTable to reflect the new data
if ($scope.tableParams) {
$scope.tableParams.reload();
} else {
// create your table as before,
// but tying it to $scope.myData
// instead of response.list
}

Multiple ng-repeat on single element

Is this possible to achieve a code like this:-
<tr ng-repeat="data in dataArray,value in valueArray">
{{data}} {{value}}
</tr>
I am having two arrays I want to show them in single row.
PS: I am not asking for syntax. I am looking for logic to achieve this
Thanks
Like :- "http://jsfiddle.net/6ob5bkcx/1/"
You should be doing this in the controller, not in the view. Map the dataValues into a key/value pair object and reference the values array using an index. This assumes that each data key has a corresponding value key.
Controller:
var dataArray = [];
var valueArray = [];
this.repeatData = dataArray.map(function(value, index) {
return {
data: value,
value: valueArray[index]
}
});
View:
<tr ng-repeat="data in repeatData">
{{data.data}} {{data.value}}
</tr>
Does this suits your need
http://jsfiddle.net/jmo65wyn/
Your data, value array as object array
this.obj = [{data: 'a', value :true}, {data: 'b', value:true}];
And you loop like this
<div ng:repeat="o in obj">
{{o.data}} and {{o.value}}
<input type="checkbox" ng:model="o.value">
</div>
Angular ng-repeat does not support it but still you can write your own custom directive according to your requirements.
Update Section
var traverseCollection = angular.module("CollectionTraverse", []);
traverseCollection.directive("repeatCollection", function(){
return {
restrict: "A",
scope: {
model: "="
},
controller: controller: function($scope) {
var collectionList = $scope.model;
angular.forEach(collectionList, function(obj, index) {
angular.forEach(obj, function(data, index) {
});
});
}
}
});
Your scope should contains the list of your collection objects : $scope.collectionList = [dataArray, valueArray];
Usage in HTML:
-------------------------------------------
<div repeat_collection model="collectionList"></div>
This directive will be generic to traverse list of collections and yes in the above code there can be some syntactical errors because i did not run it. Its your luck.
If you have, for any reason, two arrays with the same length and where their contents are corresponding (array1[0] correspond to array2[0], ..., array1[n] correspond to array2[n]), you can use AngularJS's track by (which was introduced for the 1st time in the version 1.1.4) like this for example :
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.1.4/angular.min.js"></script>
<table ng-app="" ng-init="names=['Bill','Billa','Billy']; ages=['10', '20', '30']">
<tr ng-repeat="name in names track by $index">
<td>{{ name }} is {{ ages[$index] }} years old.</td>
</tr>
</table>
Hope that can help.
if you want something like a list with two or more items in the same row:
in html file:
<li ng-repeat="item in items">
<i class="material-icons">{{navItem[1]}}</i>{{navItem[0]}}</li>
in js file:
$scope.items = [
["Home", "home"],
["Favorite", "favorite"]
]

How to filter and refresh ngtable pagination on a custom fiter

I want to filter ngtable based on value taken from dropdown box.
$scope.tableParams = new ngTableParams({
page: 1, // show first page
count: 5, // count per page
sorting: {
name: 'asc' // initial sorting
},
}, {
total: tabledata.length, // length of data
getData: function($defer, params) {
// use build-in angular filter
filteredData = params.filter() ?
$filter('filter')(tabledata, params.filter()) :
tabledata;
var orderedData = params.sorting() ?
$filter('orderBy')(filteredData, params.orderBy()) : filteredData;
$defer.resolve(orderedData.slice((params.page() - 1) * params.count(), params.page() * params.count()));
}
});
I have posted my full code on plunker: http://plnkr.co/edit/YbCe5Y6qIxN18yHCrzwW?p=preview.
Problem that occurs is that number of pages remains the same, but if some of my results were on page 5 they will remain there. Basically I have empty pages and among them will be pages with filtering result (there is no page downsizing).
I tried to incorporate my custom filter - viewFilter but I was unsuccessful in making it work. This is another plunker example where filtering is basic (based on column name) and works: http://plnkr.co/edit/CbmbXTXukNxC1ZzkJNKO?p=preview
Does anyone knows ad could help me with integration of this custom filter? Thanks
you are not invoking the filter of the table, you are just filtering the page you are on. In order to solve you issue, you should invoke the filter function of ng-table from you viewFilter function. I did few changes to your code and works as expected. In the controller I've change the values of the viewOptions, I've included a filter in the table and I've invoked the filter function from your viewFilter. Now it looks like:
$scope.viewOptions = [
{
name: 'All',
value: ''
},
{
name: 'Approved',
value: 'Y'
},
{
name: 'Declined',
value: 'N'
}
];
$scope.view = { type: '' };
$scope.viewFilter = function (data) {
var filter = $scope.view.type;
$scope.tableParams.filter(filter, data);
};
$scope.tableParams = new ngTableParams({
page: 1, // show first page
count: 10, // count per page
sorting: {
name: 'asc' // initial sorting
},
filter:{
flag_approved:''
}
}, {
total: tabledata.length, // length of data
getData: function ($defer, params) {
// use build-in angular filter
var filteredData = params.filter() ? $filter('filter')(tabledata, params.filter()) : tabledata;
var orderedData = params.sorting() ? $filter('orderBy')(filteredData, params.orderBy()) : filteredData;
params.total(filteredData.length);
$defer.resolve(orderedData.slice((params.page() - 1) * params.count(), params.page() * params.count()));
}
});
}); `
Blockquote
In the html i'm calling the viewFilter function every time that the dropdown in changed and I've removed the filter from the table. Now it looks like: `
Page: {{tableParams.page()}}
Count per page: {{tableParams.count()}}
Sorting: {{tableParams.sorting()|json}}
Filter: {{tableParams.filter()|json}}
Data: {{tableParams.ordered()|json}}
<div class="row">
<div class="col-xs-6 text-left">
<form class="filter-form form-inline" role="form">
<div class="form-group">
<label for="drop-actions">View:</label>
<select id="drop-actions" class="form-control" ng-model="view.type" ng-options="opt.value as opt.name for opt in viewOptions" ng-change="viewFilter()">
</select>
</div>
</form>
</div>
</div>
<table class="table table-bordered" ng-table="tableParams">
<tr ng-repeat="g in $data">
<td data-title="'Name'" sortable="'name'">
{{ g.name }}
</td>
<td data-title="'Head2'">
{{ g.flag_approved }}
</td>
</tr>
</table>
To fix the issue change $scope.view.type = ''; and instead put $scope.view = { type: '' };

Resources