Customizing angular filter functionality - angularjs

I am struggling in writing simple logic.
Please have a look and see if you can help me.
I have following code which shows three tables on UI at the moment based on data im returning from server.
I have search box which filter data in each table. It is also working fine.
My requirement:
I need to show one generic message "No data found" when no data found in all three tables based on input.
<div>
<input type="text" ng-model="searchStudent">
<div>
<div ng-repeat="studentPermissions in studentPermissions">
<div ng-repeat="student in studentPermissions.entities">
<table>
<thead>
<tr>
<td >Student</td>
<td>{{student.StudentName}}</td>
</tr>
<tr>
<th></th>
<th ng-repeat="permission in student.entityStudents[0].userPermissions"><div><span>{{permission.Name}}</span></div></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="student in student.entityStudents | filter:searchStudent">
<td>{{student.FirstName}} {{student.LastName}}</td>
<td ng-repeat="permission in student.userPermissions">
<input ng-model="permission.Checked" type="checkbox">
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
I have written search method in controller.
$scope.search = function (item) {
if ($scope.searchUser == null || $scope.searchStudent.trim() == "")
return true;
if (item.FirstName.toLowerCase().indexOf($scope.searchStudent.toLowerCase()) != -1 || item.LastName.toLowerCase().indexOf($scope.searchStudent.toLowerCase()) != -1 || item.Role.toLowerCase().indexOf($scope.searchStudent.toLowerCase()) != -1) {
return true;
}
return false;
};
I tried by setting flag on /off tricks but each time ended up something wrong.
My Sample Data:
$scope.studentPermissions = [
{entities[{StudentName: 'Tester', entityStudents[{FirstName: 'Test0', LastName: 'Test0', userPermissions[{prop 1, prop2, prop3}]}]}]},
{entities[{StudentName: 'Tester', entityStudents[{FirstName: 'Test1', LastName: 'Test2', userPermissions[{prop 1, prop2, prop3}]}]}]},
{entities[{StudentName: 'Tester', entityStudents[{FirstName: 'Test3', LastName: 'Test4', userPermissions[{prop 1, prop2, prop3}]}]}]},
]

You can use ngIf/ngShow/ngHide/ngClass for this, but you have to slightly change the way you write your repeat. For example, you can write it like this:
ng-repeat="student in filteredData = (student.entityStudents | filter:searchStudent)">
You can also do:
ng-repeat="student in student.entityStudents | filter:searchStudent as filteredData"
So, now you have a reference to the filteredData and you can just use filteredData.length in your ngShow/Hide/If/Class as the boolean. If it's length is 0 it will be falsy:
<p ng-hide="filteredData.length">No Data Found</p>
Here's a working demo, which I think matches your requirements, as best I can tell. Note that I moved your filter to the first nested repeat so that the tables were fully hidden if they didn't match and you only have one "No Data Found" message.
Updated Plunker

Related

AngularJS table stop sorting when in edit mode

I have AngularJS table with CRUD operations and sortable header. When I add the new row to table the lines are jumping and the table is getting sorted while in edit mode.
I want to stop sorting while in the edit mode and should sort only after saving the new row. I searched online for fixing this issue but nothing helped yet.
Here is the HTML file:
<thead>
<tr>
<td><input type="text" ng-model="main.search.Data1" id="myInput" placeholder="search for Data1..."/></td>
<td><input type="text" ng-model="main.search.Data2" id="myInput" placeholder="search for Data2..."/></td>
</tr>
<tr class="table_header" style="background-color: blue;">
<th><a href="#" ng-click="orderByField='data1'; reverseSort = !reverseSort"> Data1 <span ng-show ="!reverseSort">^</span><span ng-show="reverseSort">v</span></th>
<th><a href="#" ng-click="orderByField='data2'; reverseSort = !reverseSort"> Data2</th>
</tr>
</thead>
<tbody>
<tr ng-repeat=" code in main.Table | orderBy: Predicate | orderByField:reverseSort | filter:main.search"></tr>
<script type="text/ng-template" id="dispay">
<td>{{code.data1}}</td>
<td>{{code.data2}}</td>
</script>
<script type="text/ng-template" id="edit">
<td><input type="text" ng-model="code.data1" class"form-control input-sm"/></td>
<td><input type="text" ng-model="code.data2" class"form-control input-sm"/></td>
</script>
</tbody>
Here is the JS code:
//add new row
$scope.addNew = function(data) {
$scope.Table.unshift({
data1: "",
data2: ""
});
console.log($scope.table);
};
//Edit the row
$scope.edit = function(data){
$scope.selected = angular.copy(data);
$scope.backuplist = angular.copy($scope.table);
};
The behaviour is correct because on addNew you add 1 empty record in apply cycle which then will reorder again the list.
You have 2 ways to go :
1) When Adding new Item, create sperate object and upon submit add it in the list:
$scope.addNew = function(data) {
$scope.newItem ={
data1: "",
data2: ""
};
};
$scope.save = function() {
$scope.table.push($scope.newItem);
};
Like this there is speration of concerns and not to mingle the main list.
Or if you still want to add it in main list directly which i dont recommend you can implement your custom filter which keeps always the empty data at the top - In your predicate Method.
<tr class="table_header" style="background-color: blue;">
<th><a href="#" ng-click="orderByField='data1'; reverseSort = !reverseSort" ng-disabled="setTrueFalse"> Data1 <span ng-show ="!reverseSort">^</span><span ng-show="reverseSort">v</span></th>
<th><a href="#" ng-click="orderByField='data2'; reverseSort = !reverseSort" ng-disabled="setTrueFalse"> Data2</th>
</tr>
$scope.setTrueFalse = true/false
MAke use of ng-disabled.. Set it to true when you do not want to sort the values and vice versa

Applying sort and filter to an Angular table

I downloaded an Angular demo app to learn and work my way through Angular basics. I am having issue with applying a filter and sort to a data table. I made it by referring some examples and not sure if it is correct.
My table is :
<div class="widget-content" ng-controller="getAllBenchersController">
<table ng-table="talentPoolList" show-filter="true" class="table table-striped table-bordered">
<tr ng-repeat="employee in data | filter: testFilter">
<td data-title="'#'">{{$index + 1}}</td>
<td data-title="'Employee ID'" sortable="'empno'" filter="{ 'empno': 'text' }">
{{employee.employee.employeeNo}}
</td>
<td data-title="'First Name'" sortable="'employee.employee.firstName'" filter="{ 'employee.employee.firstName': 'text' }">
{{employee.employee.firstName}}
</td>
</tr>
</table>
</div>
Controller :
myApp.controller('getAllBenchersController', ['$scope', 'employeeTalentPoolServices', function ($scope, employeeTalentPoolServices) {
employeeTalentPoolServices.getAllBenchers().then(function (result) {
$scope.data = result.data;
$scope.testFilter = function (item) {
return (item.state.state.toLowerCase() === 'available' || item.state.state.toLowerCase() === 'blocked');
}
});
I have no clue how it works. Can anyone explain and provide a solution to fix this issue?
Thanks in advance
So to explain your demo example I've created a similar example to make you understand what's happening in your question.
We have a employees data with different statuses so when I want to display the list of employees I just want show 'fair' and 'good' so I've written a filter function passed to filter directive to tell what items should be displayed from the list.
If you observe the function it takes every item from list and checks for status to match the desired statuses for displaying.
Check out the demo for the same, hope this gives you a clear understanding on what's happening in your Demo app.
var app = angular.module('app',[]);
app.controller('getAllBenchersController',function($scope,$filter){
$scope.data = {employee:[
{'no':1,'name':'max','status':'bad'},
{'no':2,'name':'fox','status':'good'},
{'no':3,'name':'juno','status':'bad'},
{'no':4,'name':'pet','status':'fair'},
{'no':5,'name':'xyz','status':'good'},
{'no':6,'name':'shit','status':'bad'},
{'no':7,'name':'doggy','status':'fair'},
{'no':8,'name':'hmmm','status':'bad'}
]}
//this test filter is a function which allows me to decide which data should be displayed in this case I've used 'fair' & 'good' status employees to be displayed...
$scope.testFilter = function (item) {
return (item.status.toLowerCase() === 'good' || item.status.toLowerCase() === 'fair');
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" class="widget-content" ng-controller="getAllBenchersController">
<table>
<tr ng-repeat="emp in data.employee | filter: testFilter">
<td>{{$index+1}} </td>
<td> {{emp.no}}</td>
<td>{{emp.name}} </td>
</tr>
</table>
</div>

assign whole object for ng-value and retrieve in controller when the a particular radio button is checked

I want to assign and retrieve the whole object to ng-value on ng-repeat. And when I select a row of table using radio button, I want to get the object of the selected row.
HTML:
<button ng-click="save()">Save</button>
<table id="remark-table">
<thead>
<tr>
<th>Name</th>
<th>Remarks</th>
<th>Indicator</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="data in remarks track by data.id">
<td>{{data.name}}</td>
<td>{{data.remarks}}</td>
<td><input type="radio" name="indicator" ng-model=data ng-value=data></td>
</tr>
</tbody>
</table>
JS:
$scope.remarks = [{
name : 'John',
remarks : 'Remark 1'
},
{
name : 'Tom',
remarks : 'Remark 2'
},
{
name : 'Jerry',
remarks : 'Remark 3'
}];
$scope.save = function() {
var remarks = angular.element('#remark-table tbody tr td').find('input[name="indicator"]:checked').val();
}
remarks is returned as [object Object]
Fiddle is not opening at the moment. Hence posted the code here. Kindly help with this. Thanks in advance!
Try it like this in the html:
<input type="radio" name="indicator" ng-model="$parent.data" ng-value="data">
And in the controller you can get it like this:
$scope.save = function() {
var remarks = $scope.data;
}
Didnt actually tested, so try it out and see if it works...

AngularJS non-ascii property name support

I don't know how to use non-ascii property name in AngularJS. I could print a value by using a['property_name'] instead of a.property_name, but I couldn't use the same way in 'orderBy'. If I click on 'name', sorting would happen, but if I click on '가격_price', nothing would happen and an error would show up in the console. How could I sort a table which has non-ascii name?
(There are Korean Characters in the code, but I think it makes sense.)
http://jsfiddle.net/k9h32mh9/
<div ng-app>
<div ng-controller="ListCtrl">
<table>
<tr>
<th><a ng-click="predicate='name'; reverse=false">name</a></th>
<th><a ng-click="predicate='가격_price'; reverse=false">가격(price)</a></th>
</tr>
<tr ng-repeat="item in items | orderBy:predicate:reverse">
<td>{{item.name}}</td>
<td>{{item['가격_price']}}</td>
</tr>
</table>
</div>
</div>
<script>
function ListCtrl($scope, $http) {
$scope.predicate = '-name';
$scope.items = [{name: "a", 가격_price:"1000"},
{name: "b", 가격_price:"2000"},
{name: "c", 가격_price:"1500"}];
}
</script>
While this is an issue with Angular, as per https://github.com/angular/angular.js/issues/2174, it can be worked around by specifying your own predicate function on the scope in order to access the property to sort by:
$scope.predicateProperty = 'name';
$scope.predicate = function(a) {
return a[$scope.predicateProperty];
};
And the HTML can be almost identical, just setting predicateProperty to the property name that you want to sort by (I've also removed references to "reverse" as it slightly complicates the issue)
<table>
<tr>
<th><a ng-click="predicateProperty='name';">name</a></th>
<th><a ng-click="predicateProperty='가격_price';">가격(price)</a></th>
</tr>
<tr ng-repeat="item in items | orderBy:predicate">
<td>{{item.name}}</td>
<td>{{item['가격_price']}}</td>
</tr>
</table>
You can see this working at http://jsfiddle.net/k9h32mh9/5/

Get ng-repeat to use object property order

I have a dynamic dataset to present with Angular. In other words I do not have access to the column names returned until runtime.
I can present the column names as a header and the data itself with no problem. ng-repeat (or perhaps it's JS itself) though refuses to return the columns in the order they were created. You can see in the fiddle the columns are sorted so they appear "age name weight", I need them the way they came, "name age weight"
I created another array of the column names and their proper order ($scope.order) but I cannot seem to find a way to use that with Angular to sort the data.
Please give me a way to present this data in the original order.
I created a JSFiddle: http://jsfiddle.net/GE7SW/
Here's a simple scope that sets up the data:
function MainCtrl($scope) {
$scope.output = [
{
"name": "Tom",
"age": "25",
"weight" : 250
},
{
"name": "Allan",
"age": "28",
"weight" : 175
},
{
"name": "Sally",
"age": "35",
"weight" : 150
}
];
$scope.order = {
"name": 1,
"age": 2,
"weight" : 3
};
}
Here's the HTML:
<table ng-app ng-controller="MainCtrl">
<thead>
<tr>
<th ng-repeat="(key,value) in output.0">{{key}}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in output">
<td ng-repeat="(key,value) in row">{{value}}</td>
</tr>
</tbody>
</table>
(Note the (key,value) in the last ng-repeat is needed by ng-class code I took out for this example.)
The properties order in JavaScript objects is never guaranteed. You need to use a list.
The only thing you need to do is convert $scope.order into an array:
$scope.order = [
"name",
"age",
"weight"
];
and use that inside the HTML like this:
<table ng-app ng-controller="MainCtrl">
<thead>
<tr>
<th ng-repeat="key in order">{{key}}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in output">
<td ng-repeat="key in order">{{row[key]}}</td>
</tr>
</tbody>
</table>
Fiddle
Your updated fiddle here (click).
While the order of javascript objects is not guaranteed, this is likely to work in most or all cases. This is simply looping your objects into arrays. It might be a better approach, if possible, to have the data coming from the server in arrays, 1 that describes the structure (keys) and the other that just data sets of arrays.
$scope.getRow = function(row) {
var arr = [];
for (var k in row) {
if (k !== '$$hashKey') {
arr.push(row[k]);
}
}
return arr;
};
$scope.getKeys = function(row) {
var arr = [];
for (var k in row) {
if (k !== '$$hashKey') {
arr.push(k);
}
}
return arr;
};
the html:
<table ng-app ng-controller="MainCtrl">
<thead>
<tr>
<th ng-repeat="(key,value) in getKeys(output[0])">{{value}}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in output">
<td ng-repeat="(key, value) in getRow(row)" ng-class="getKeys(output[0])[key]">{{value}}</td>
</tr>
</tbody>
</table>

Resources