Angular orderBy and scope - angularjs

I'm wondering how to properly sort table data when the data is spread accross multiple tables. I have some app data that is displayed in tables based on the country the app belongs to, i.e., each country has its own table of app data. I'm able to sort the table data by clicking the table headings (app properties), using orderBy, but clicking the heading of one of the country tables sorts all of the country tables. I'm wondering how to isolate the scope so that clicking on the table heading of one country's table of app data only changes the order of it's app data and not the other countries tables of app data. I tried adding the countryId property to the app data and then filtering based on the currently clicked country table but that just causes the other country tables to be empty. What's the proper way to isolate the scope of orderBy?
<div class="table-responsive" ng-repeat="countryReleases in regionRelease.countryReleases">
<h5><strong>{{ countryReleases.countryName }}</strong></h5>
<table id="app" class="table table-striped table-bordered table-condensed">
<thead>
<tr>
<th ng-click="vm.sortCountry = countryReleases.countryId; vm.sortName = 'application.name'; vm.sortReverse = !vm.sortReverse">
<span>App Name</span>
<span ng-show="vm.sortName == 'application.name' && !vm.sortReverse" class="pull-right fa fa-caret-up"></span>
<span ng-show="vm.sortName == 'application.name' && vm.sortReverse" class="pull-right fa fa-caret-down"></span>
</th>
<th>App Prop 2</th>
...
</tr>
</thead>
<tbody>
<tr ng-repeat="appReleases in countryReleases.appReleases | filter:vm.sortCountry | orderBy:vm.sortName:vm.sortReverse">
<td>
<img class="thumbnail" ng-src="{{ appReleases.application.icon }}">
...
// Edit:
fixed by passing the scope of the current iteration to orderBy filter in the controller:
<th ng-click="vm.sortName = 'application.name'; vm.sortReverse = !vm.sortReverse; vm.orderByAppCountry(this, vm.sortName, vm.sortReverse)">
...
<tr ng-repeat="appReleases in countryReleases.appReleases">
...
function orderByAppCountry(scope, predicate, reverse) {
scope.countryReleases.appReleases = $filter('orderBy')(scope.countryReleases.appReleases, predicate, reverse);
}

Fixed by adding orderBy filter to controller and calling from click of country table, See edit above.

Related

AngularJs - allow only one item to be selected in Table

I am using smart table. I have a logic behind where I only need one item to be selected. My current table code allow multiple lines to be selected.
This is my HTML:
<table st-safe-src="flow3.dataSet" st-table="flow3.displayed" class="table table-striped">
<thead>
<tr>
<th st-sort="method">Method</th>
<th st-sort="sample">Sample</th>
<th st-sort="parameters">Parameters</th>
</tr>
</thead>
<tbody ui-sortable ng-model="flow3.displayed">
<tr ng-repeat="row in flow3.displayed track by $index" style="cursor: move;" ng-click="row.selected = !row.selected; flow3.selectRow($event, row)" ng-class="{success: row.selected}">
<td>{{row.method.name}}</td>
<td>{{row.sample}}</td>
<td>
<span ng-repeat="parameter in row.parameters">{{parameter.methodInputParameter.name}} : {{parameter.value}}<br/></span>
</td>
<td>
<button type="button" ng-click="flow3.removeItem(row)"
class="btn btn-danger btn-sm btn-round pull-right"
ng-disabled="flow3.confirmDisabled">
<i class="glyphicon glyphicon-trash"></i>
</button>
</td>
</tr>
</tbody>
</table>
This is my JS:
flow3.selectRow = function($event, row) {
flow3.selectedItem = row;
}
If you want the only one row with selected property set to true, you should modify your selectRow method to accept the collection of all rows and then de-select all before selecting clicked one:
flow3.selectRow = function($event, row, rows) {
//de-select all
angular.forEach(rows, function(r){ r.selected = false; });
//select clicked
row.selected = true;
flow3.selectedItem = row;
}
ng-click="flow3.selectRow($event, row, flow3.dataSet)"
If you want to apply different css class to the clicked/selected item you probably can leave your selectRow method as is (since we have the selected item as flow3.selectedItem) and change the condition in the ngClass directive to be (if rows have some unique id property for example):
ng-class="{success: row.id === flow3.selectedItem.id}"
Hope this helps.
I'd recommend looking at the smart table github page and use guide here.
In particular the section relevant to your question is 'Select Data Rows'.
Essentially you need to use the st-select-row attribute along with the st-select-mode to configure click within your table row (tr) elements.

Filter a table based on only particular filed in angular js

I am doing a search in my table content, at a particular time I want to filter my table only based on the particular field.
For example, I have a table with number, name and content column. When I enter text in the search box it should search the matched value only in number and name, not the content. How to do this in angular js.
You can supply a filter function to your ng-repeat assuming your code is structured like the following,
<table>
<thead>
<th>
<td>Number</td>
<td>Name</td>
<td>Content</td>
</th>
<thead>
<tbody>
<tr ng-repeat="item in ctrl.items | filter : ctrl.filterOnNameAndNumber">
<td>{{item.number}}</td>
<td>{{item.name}}</td>
<td>{{item.content}}</td>
</tr>
</tbody>
</table>
ctrl.filterOnNameAndNumber = function (item) {
// filter logic here
return item.name.indexOf(ctrl.search) > -1 || item.number === ctrl.search;
}
Fore more information, read the following API docs,
https://docs.angularjs.org/api/ng/filter/filter
You can try
ui-grid
instead table.

Datatables search, filter, and export with Firebase

I have a CRUD app powered by angular. Recently I added datatables to it in order to search, filter, sort,export and hide columns using the power of datatables. Unfortunately it returns the Firebase references in the various columns {{contact.name}} {{contact.email}} (There are 4 more columns) when I use any datatables feature such as search it returns the Firebase reference instead of a field. Is there a way to fix this? I really need those datatable features at the same time use Firebase.
$(document).ready(function() {
$('#contacts').DataTable( {
dom: 'Bfrtip',
buttons: [
'copyHtml5',
'excelHtml5',
'csvHtml5',
'pdfHtml5'
]
} );
} );
<table id="contacts" class="table table-striped table-hover" >
<thead>
<tr>
<th>Name</th>
<th>Phone</th>
<th>Area</th>
<th>Occupation</th>
<th>E-mail</th>
<th> Actions </th>
</tr>
</thead>
<tbody>
<tr ng-repeat="contact in contacts">
<td>{{contact.name}}</td>
<td>{{contact.phone}}</td>
<td>{{contact.area}}</td>
<td>{{contact.work}}</td>
<td>{{contact.email}}</td>
<td>Edit <a class="btn btn-raised btn-xs btn-danger" ng-click="removeContact(contact.$id)">Delete</a></td>
</tr>
</tbody>
</table>
EDIT
Will sourcing the data via ajax sort this out. This is the json format i get from the ajax GET request
{"-KIZ6VnucsKbKjlaE8aq":{"area":"Parklands","email":"tttt","name":"Mohammed Sohail","phone":"+254700000000","work":"ttt"},"-KId6OC2gOwiacUid9yK":{"area":"dfgdfg","email":"dfgdf","name":"dfg","phone":"dfgdfg","work":"fdfffffff"},"-KId6Rqo0B6w0jACHhWM":{"area":"dfgdfgdfgdf","email":"dfgdfgdfgdfg","name":"dfgfdgdf","phone":"gdfgdfgdfg","work":"gdfgdfgdfgdfg"},"-KIqmYZubPYhAqDqEyWo":{"area":"dfgfdg","email":"fgfdgfdgdf","name":"fgfg","phone":"fdgdg","work":"fgdfgdf"},"-KIqn5QABMXrTGoVgQv1":{"area":"bla","email":"weadasda","name":"bla","phone":"bla","work":"bla"}}
And this is how the data looks like on the console.
Any help to use data tables will be appriciated.
FireBase database image
So, this question is really about turning a (firebase) JSON object of objects with unknown object entry names such as KId6Rqo0B6w0jACHhWM into a more plain structure that can be used along with dataTables and ng-repeat?
You can format contacts into an array of plain objects this way :
$http.get('firebase.json').then(function(json) { //faked response from firebase
$scope.contacts = []
for (var item in json.data) {
$scope.contacts.push(json.data[item])
}
})
Now the ng-repeat will work and the markup (or contacts data) is understandable for dataTables. To turn this into angular-datatables (angular directives for jQuery dataTables) the only thing you need to do is to include the datatables dependency and include the datatable directive in the markup :
<table datatable="ng" class="table table-striped table-hover" >
demo -> http://plnkr.co/edit/tn9cuKa46vs4x8cHebjB?p=preview

Angular ng-repeat stay paged after filter

I'm using AngularJS and I have a simple table using ng-repeat and filter. When i insert anything at the search input it filters OK but it keeps paginated as it was before I filter the table. Any ideas why this is happening ?
Here's my code:
//some var initialization
$scope.pagina = {};
$scope.pagina.currentPage = 1,
$scope.pagina.numPerPage = 10,
$scope.pagina.maxSize = 5;
//return from server with data
coresFactory.getCores().then(function(response) {
$scope.tabelaCores = response.data;
$scope.filteredTodos = $scope.tabelaCores.cores.slice(0, 10);
});
//do pagination
$scope.$watch('pagina.currentPage', function() {
var begin = (($scope.pagina.currentPage - 1) * $scope.pagina.numPerPage),
end = begin + $scope.pagina.numPerPage;
$scope.filteredTodos = $scope.tabelaCores.cores.slice(begin, end);
},true);
<input ng-model="pesquisaTabela" type="search" style="width:300px;" class="form-control input-inline" placeholder="" aria-controls="sample_1"></label>
<table class="table" style="margin-bottom:5px;border:1px solid #DDDDDD" id="sample_1">
<thead>
<tr style="background-color:#F9F9F9">
<th style="width:100px; text-align:center;"> Id </th>
<th> Nome </th>
<th> Plural </th>
<th style="width:100px; text-align:center;"> Ativo </th>
</tr>
</thead>
<tbody>
<tr ng-repeat="cor in filteredTodos | filter:pesquisaTabela" ng-click="setSelected(cor.id)" ng-class="{linhaSelected: cor.id === idCorSelecionada}">
<td style="text-align:center;"> {{cor.id}} </td>
<td style="text-transform:capitalize"> {{cor.nome}} </td>
<td style="text-transform:capitalize"> {{cor.plural}} </td>
<td style="text-align:center;">
<span ng-if="cor.status=='sim'" class="label label-sm label-success"> Sim </span>
<span ng-if="cor.status=='nao'" class="label label-sm label-danger"> Não </span>
</td>
</tr>
</tbody>
</table>
<pagination first-text="<<" last-text=">>" next-text=">" previous-text="<" ng-model="pagina.currentPage" total-items="tabelaCores.cores.length" max-size="pagina.maxSize" boundary-links="true"></pagination>
You have quite a disconnect between various parts
Pagination is working off of one array, display from another and filter from yet another because when filter kicks in it returns a new filtered array.
The way you have things structured, your filter won't work properly either.
When you slice the main data array the filter is only going to work on that part that is sliced....not the whole main array
In order for pagination to be synchronized with filtering your simplest start point would likely be do your own filtering and share the same filtered array between the pagination and the table.
There are some other built in filters that you could use also like limitTo that takes 2 arguments limit and begin. That would help you get rid of currrent slice
There are lots of available grid/table directives available.
Using one of those would be my best suggestion
There is one other way you could do this all in the view. There is a syntax for ng-repeat that creates a new filtered array on the scope and therefore gives you access to it's length
<tr ng-repeat="row in filteredData = ( data |filter:pesquisaTabela | limitTo:10:start)">
Using this you could pass filteredData array to the total-items of the pagination directive.
It also now lets you do things like:
<div> Filtered length is: {{filteredData.length}}</div>

How to get the selected item after filtering in angularjs?

I have the following:
<table class="table table-striped">
<thead>
<tr>
<th>Name</th>
<th>Url</th>
<th>Published</th>
<th>Import</th>
</tr>
</thead>
<tr ng-repeat="catalogObject in catalog | filter:catalogueSearchText |
orderBy:sortOrder:true"">
<td>{{catalogObject.name}}</td>
<td>{{catalogObject.url}}</td>
<td>{{catalogObject.published}}</td>
<td style="text-align:center">
<div class="btn btn-primary"
ng-click="ok(catalogObject.originalPosition)">✔</div></td>
</tr>
</table>
I have created the originalPosition property so that once I have filtered my catalog I know exactly what position the selected object is in the catalog scoped list.
Is there a better way than creating this additional property on my collection using a more declarative approach?
So basically I need a way to get access to the selected item once the original list has been filtered and sorted (before I just used $index in ng-click = "ok($index") however this index does not correspond to the original position of the elements in my catalog list).
You want to access the original object, but you already have this object!
All you have to do is make a small modification to your ok() function, so that it works for ok(catalogObject)

Resources