SortBy not Sorting correctly? - javascript

I have a table with this ng-repeat
ticket in filteredTickets = (vm.tickets | filter : vm.search | orderBy : vm.propertyName : vm.reverse | limitTo:vm.itemsPerPage:vm.itemsPerPage*(vm.currentPage-1))
My thead call a function on ng-click
ng-click="vm.sortBy('title');"
And in my controller
// table ordering
vm.propertyName = 'ticketID'; // default order
vm.reverse = true;
vm.sortBy = function(propertyName) {
vm.reverse = (vm.propertyName === propertyName) ? !vm.reverse : false;
vm.propertyName = propertyName;
}
but it's not ordering well. I have multiple columns, some with integers other with strings and doesnt order correctly (it orders but randomly)
Any help?

You have limiTo filter, so when you change value of vm.propertyName you can see quite another set of tickets(not current, but with new sorting), may be exactly that creates for you a sensation of "random" sorting? At this case, you can set vm.currentPage = 1 inside vm.sortBy method to start new overview from first page or place limitTo filter before orderBy to fix current page and only then apply sorting to items in it, as shown below:
angular.module('app', []).controller('ctrl', function($scope){
var vm = this;
vm.propertyName = 'ticketID';
vm.itemsPerPage = 5;
vm.currentPage = 1;
vm.tickets = [];
for(var i = 0; i < 100; i++)
vm.tickets.push({
ticketID: i,
name: 'Name' + (100 - i)
})
vm.sortBy = function(propertyName) {
vm.reverse = (vm.propertyName === propertyName) ? !vm.reverse : false;
vm.propertyName = propertyName;
//or simply vm.currentPage = 1; without rest of stuff
}
vm.pages = function(value){
return Math.ceil(value);
}
})
<script src="//code.angularjs.org/snapshot/angular.min.js"></script>
<div ng-app='app' ng-controller='ctrl as vm'>
search by: <input type='text' ng-model='vm.search'/>
<br>
<button ng-click='vm.sortBy("ticketID")'>Sort by ticketID</button>
<button ng-click='vm.sortBy("name")'>Sort by name</button>
<ul>
<li ng-repeat='ticket in filteredTickets = (vm.tickets | filter : vm.search | limitTo : vm.itemsPerPage : vm.itemsPerPage * (vm.currentPage - 1)) | orderBy : vm.propertyName : vm.reverse'>
{{ticket}}
</li>
</ul>
<button ng-disabled='vm.currentPage == 1' ng-click='vm.currentPage = vm.currentPage - 1'>Prev</button>
<button disabled>{{vm.currentPage}}</button>
<button ng-disabled='vm.currentPage == vm.pages((vm.tickets | filter : vm.search).length / vm.itemsPerPage)' ng-click='vm.currentPage = vm.currentPage + 1'>Next</button>
</div>

Related

Custom filter for comparing dates in angularjs

I want to display only items from list that are between the two selected dates from input fields. This is my custom controller:
// Custom filter for comparing dates
snippet.filter('snippetsByDate', function(){
return function(items, fromDate, toDate){
var filtered = [];
//here you will have your desired input
var from_date = Date.parse(fromDate);
var to_date = Date.parse(toDate);
alert("From dateeeee " + from_date);
angular.forEach(items, function(item) {
if(Date.parse(item.created) >= from_date && Date.parse(item.created) <= to_date) {
filtered.push(item);
}
});
return filtered;
};
});
The alert() in the filter's function is returning undefined for the variable fromDate and NaN for the variable from_date. This is how I call my filter:
<tr ng-repeat="s in snippets | filter:description | snippetsByDate : from_date : to_date">
<td>{{s.description}}</td>
<td>{{s.language}}</td>
<td>{{s.url}}</td>
<td>{{s.user}}</td>
</tr>
And my input fields are below this code (don't know if that metters) and look like this:
<label>Filter snippets by date</label><br>
<label>From: </label>
<input type="date" ng-model="from_date"><br>
<label>To: </label>
<input type="date" ng-model="to_date">
When I delete the custom filter from ng-repeat it is working fine, but with that it looks like I am getting empty list.
I should mention that in my class I have variable created as java.util.Date class.
Thank you in advance.
Please check this working code.
var snippet = angular.module('plunker', []);
snippet.filter('snippetsByDate', function () {
return function (items, fromDate, toDate) {
var filtered = [];
//here you will have your desired input
var from_date = Date.parse(fromDate);
var to_date = Date.parse(toDate);
if (from_date == null || toDate == null)
filtered = items;
else
filtered = items.filter(function (item) {
return item.created >= from_date && item.created <= to_date;
});
return filtered;
};
});
snippet.controller('MainCtrl', function ($scope) {
$scope.snippets = [];
for (var i = 0; i < 11; i++) {
$scope.snippets.push({
description: 'description-' + i,
language: i % 2 == 0 ? 'Hindi' : 'English',
url: 'url-' + i,
user: 'User-' + i,
created: new Date().setMonth(i)
});
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.14/angular.min.js" ></script>
<div ng-app="plunker" ng-controller="MainCtrl">
<table>
<tr>
<td>
<label>Filter snippets by date</label><br>
<label>From: </label>
<input type="date" ng-model="from_date"><br>
<label>To: </label>
<input type="date" ng-model="to_date">
</td>
</tr>
<tr ng-repeat="s in snippets | filter:description | snippetsByDate : from_date : to_date">
<td>{{s.description}}</td>
<td>{{s.language}}</td>
<td>{{s.url}}</td>
<td>{{s.user}}</td>
</tr>
</table>
</div>

Set the value of a nested radio button

I have many list of radio button in a ng-repeat.
I've succeded for get the selected item.
Now I try to set the default value of the radio.
Can some one help me please. Here my code for the button.
Thank's
VariableRadioArr2 = [{"id":"21","libelle":"P15m","type":"radio","valeur_1":"Oui","valeur_2":"Non","valeur_3":"","valeur_4":"","valeur_5":"","valeur_6":"","valeur_7":"","valeur_8":"","valeur_9":"","valeur_10":""},{"id":"25","libelle":"Surface (m²)","type":"input","valeur_1":"","valeur_2":"","valeur_3":"","valeur_4":"","valeur_5":"","valeur_6":"","valeur_7":"","valeur_8":"","valeur_9":"","valeur_10":""},{"id":"36","libelle":"p16","type":"radio","valeur_1":"Oui","valeur_2":"Non","valeur_3":"","valeur_4":"","valeur_5":"","valeur_6":"","valeur_7":"","valeur_8":"","valeur_9":"","valeur_10":""}]
$scope.itemGroups = VariableRadioArr2;
console.log(VariableRadioArr2);
//$scope.selected = 1;
$scope.VariableRadioToggle2 = true;
$scope.clickedVariableRadio2 = function(test)
{
$scope.clickedVariableRadio2_select = JSON.parse(JSON.stringify($scope.itemGroups));
}
if(VariableRadioArr2.length == 0)
{
$scope.clickedVariableRadio2_select = [];
$scope.VariableRadioToggle2 = false;
}
<ion-list id="page-list7" ng-show="VariableRadioToggle2">
<div ng-repeat="itemGrp in itemGroups">
<ion-item class="item-divider" id="page-list-item-divider32">{{itemGrp.name}}</ion-item>
<ion-toggle name="{{itemGrp.name}}" ng-click="clickedVariableRadio2(portion.selected)" ng-repeat="(key,portion) in itemGrp.Portions" ng-model="itemGrp.selected_item" ng-true-value="'{{key}}'" ng-false-value="">{{portion.name}}</ion-toggle>
</div>
</ion-list>
Here I'm doing a loop from 1-10 to copy the values into a new object and delete the old ones.
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
var Variable = [{"id":"21","libelle":"P15m","type":"radio","valeur_1":"Oui","valeur_2":"Non","valeur_3":"","valeur_4":"","valeur_5":"","valeur_6":"","valeur_7":"","valeur_8":"","valeur_9":"","valeur_10":""},{"id":"25","libelle":"Surface (m²)","type":"input","valeur_1":"","valeur_2":"","valeur_3":"","valeur_4":"","valeur_5":"","valeur_6":"","valeur_7":"","valeur_8":"","valeur_9":"","valeur_10":""},{"id":"36","libelle":"p16","type":"radio","valeur_1":"Oui","valeur_2":"Non","valeur_3":"","valeur_4":"","valeur_5":"","valeur_6":"","valeur_7":"","valeur_8":"","valeur_9":"","valeur_10":""}];
// Create sub object for all values
// and delete the old values
for (i = 0; i < Variable.length; i++) {
Variable[i].values = {};
Variable[i].selected = '';
for (v = 1; v < 11; v++) {
if(Variable[i]['valeur_'+v] != undefined){
Variable[i].values['valeur_'+v] = Variable[i]['valeur_'+v];
delete Variable[i]['valeur_'+v];
}
}
}
$scope.itemGroups = Variable;
// Set defaults
// By index
$scope.itemGroups[1].selected = 'valeur_4';
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.1/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
<div ng-repeat="itemGrp in itemGroups">
<div>{{itemGrp.libelle}}</div>
<label ng-repeat="(key, value) in itemGrp.values">
<input type="radio" name="{{itemGrp.id}}" ng-model="itemGrp.selected" ng-value="key">{{value}}
</label>
</div>
</div>

AngularJS. Multiple conditions in Filter in ng-repeat

Why my condition doesn't work if I put the first of any condition.
I put 100 in the PriceTo => I get all items, where price > 100
I put "App" in the Name => nothing changes
But I should get items where (price > 100) AND (Name contains "App").
fiddle: http://jsfiddle.net/QHtD8/142/
JS:
var myApp = angular.module('myApp', []);
function MyCtrl($scope) {
$scope.products = [
{name:"Apple",type:"fruit",price:100},
{name:"Grape",type:"fruit",price:500},
{name:"Orage",type:"fruit",price:555},
{name:"Carrot",type:"vegetable",price:1000},
{name:"Milk",type:"dairy",price:800}
];
$scope.productFilter = function (item) {1
var result = item.name === $scope.foodName ||
item.price >= $scope.priceFrom ||
item.price <= $scope.priceTo;
return result;
};
}
HTML:
<div ng-controller="MyCtrl">
Name
<input ng-model="foodName" /><br>
Price from
<input ng-model="priceFrom" /><br>
Price to
<input ng-model="priceTo" /><br>
<ul>
<li ng-repeat="item in products | filter:productFilter">
{{item.name}} - {{item.price}}
</li>
</ul>
</div>
Example
You have a wrong conditions in your filtration function.
Try the following:
$scope.productFilter = function (item) {
var result = (!$scope.foodName || item.name.toLowerCase().includes($scope.foodName.toLowerCase())) &&
(!$scope.priceFrom || item.price >= $scope.priceFrom) &&
(!$scope.priceTo || item.price <= $scope.priceTo);
return result;
};
Here is jsfiddle

how to make a correct search when pagination

I can not understand. How to make a correct search when pagination?
English for bad writing.
I did so:
var app = angular.module('appTelDirectory', []);
app.controller('directoryList', function($scope) {
$scope.currentPage = 0;
$scope.pageSize = 10;
$scope.users = [{}]
$scope.numberOfPages = function() {
return Math.ceil($scope.users.length / $scope.pageSize);
}
for (var i = 0; i < 45; i++) {
$scope.users.push({
'name': 'user' + i
});
}
});
app.filter('startFrom', function() {
return function(input, start) {
start = +start; //parse to int
return input.slice(start);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="appTelDirectory" ng-controller="directoryList">
<input placeholder="Поиск..." ng-model="searchAll" class="form-control">
<ul>
<li ng-repeat="item in users | filter:searchAll | startFrom:currentPage*pageSize | limitTo:pageSize">{{item.name}}</li>
</ul>
<table>
<tr ng-repeat="item in users | startFrom:currentPage*pageSize | limitTo:pageSize">
</table>
<button ng-disabled="currentPage == 0" ng-click="currentPage=currentPage-1">Previous</button>
{{currentPage+1}}/{{numberOfPages()}}
<button ng-disabled="currentPage >= users.length/pageSize - 1" ng-click="currentPage=currentPage+1">
Next
</button>
</div>
How do I change the number of items, depending on the user list. NumberOfPages unchanged...
You can use a separate list for it like this. Basically, I'm using another list filteredUsers. Now instead of using filter in the view i.e. filter:searchAll, I'm doing the same thing using the underlying $filter service in the $watch which will be invoked as I type in the field.
Now, we always have the filtered users in the filteredUsers scope variable so your further calculation now can be based on the $scope.filteredUsers not on $scope.users.
var app = angular.module('appTelDirectory', []);
app.controller('directoryList', function($scope, $filter) {
$scope.currentPage = 0;
$scope.pageSize = 10;
$scope.users = [{}];
// Using a separate list of filtered users
$scope.filteredUsers = [{}];
$scope.numberOfPages = function() {
return Math.ceil($scope.filteredUsers.length / $scope.pageSize);
}
for (var i = 0; i < 45; i++) {
$scope.users.push({
'name': 'user' + i
});
}
$scope.filteredUsers = angular.copy($scope.users);
$scope.$watch('searchAll', function(newValue) {
// Manually filtering here instead doing in the view
$scope.filteredUsers = $filter('filter')($scope.users, {$: newValue});
});
});
app.filter('startFrom', function() {
return function(input, start) {
start = +start; //parse to int
return input.slice(start);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="appTelDirectory" ng-controller="directoryList">
<input placeholder="Поиск..." ng-model="searchAll" class="form-control">
<ul>
<li ng-repeat="item in filteredUsers | startFrom:currentPage*pageSize | limitTo:pageSize">{{item.name}}</li>
</ul>
<table>
<tr ng-repeat="item in users | startFrom:currentPage*pageSize | limitTo:pageSize">
</table>
<button ng-disabled="currentPage == 0" ng-click="currentPage=currentPage-1">Previous</button>
{{currentPage+1}}/{{numberOfPages()}}
<button ng-disabled="currentPage >= filteredUsers.length/pageSize - 1" ng-click="currentPage=currentPage+1">
Next
</button>
</div>

Populate table from JSON with search

I was able to purely implement a grid from a JSON object - AngularJS ng-repeat to populate grid from array. However, due to the nature of the added indices, being able to create a search bar with ng-model and filter:search does not work - it only can search for the first in each table row.
var test= angular.module("app", []);
test.controller("appControl", function($scope, $http) {
$http.get("http://www.w3schools.com/angular/customers.php")
.success(function (response) {
$scope.data = response.records;
}
);
$scope.getFiltered= function(obj, idx){
//Set a property on the item being repeated with its actual index
//return true only for every 1st item in 5 items
return !((obj._index = idx) % 5);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<body ng-app='app' ng-controller='appControl'>
<input type='text' ng-model='search.Country' />
<table>
<tr ng-repeat="work in data | filter:getFiltered | filter:search">
<td>{{work.Country}}</td>
<td>{{data[work._index+1].Country}}</td>
<td>{{data[work._index+2].Country}}</td>
<td>{{data[work._index+3].Country}}</td>
<td>{{data[work._index+4].Country}}</td>
</tr>
</table>
</body>
The length of data may or not cause the table to look like a perfect rectangle.
I'm working on making a function to split up the array and create the grid in JavaScript itself, but I'm still not sure how to filter it via search input.
Second try (with the mentioned function, but no filters at all yet...):
var test= angular.module("app", []);
function createGrid(arr, width) {
newArr = [];
reps = Math.ceil(arr.length/width) * width;
k = 0;
for (var i = 0; i < reps/width; i++) {
newArr[i] = [];
}
for (var i = 0; i < reps/width; i++) {
for (var j = 0; j < width; j++) {
(arr[k]) ? newArr[i][j] = arr[k] : newArr[i][j] = "";
//console.log(i, j, arr[k]);
k++;
}
}
return newArr;
}
test.controller("appControl", function($scope, $http) {
$scope.gridWidth = 4;
$http.get("http://www.w3schools.com/angular/customers.php")
.success(function (response) {
$scope.data = createGrid(Object.keys(response.records).map(function(k) { return response.records[k] }), $scope.gridWidth);
}
);
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<body ng-app='app' ng-controller='appControl'>
<input type='text' ng-model='search.Country' />
<table>
<tr ng-repeat="row in data">
<td ng-repeat='work in row'>
{{ work.Country }}
</td>
</tr>
</table>
</body>
You could try something like this:
var test= angular.module("app", []);
test.controller("appControl", function($scope, $http) {
$http.get("http://www.w3schools.com/angular/customers.php")
.success(function (response) {
$scope.data = response.records;
$scope.filteredData= response.records;
}
);
$scope.$watch('search', function () {
var array=[];
for(var i in $scope.data)
{
if($scope.search==undefined || $scope.search.length == 0 || ($scope.data[i].Country!=undefined&&$scope.data[i].Country.toUpperCase().startsWith($scope.search.toUpperCase()))){
array.push($scope.data[i]);
}
}
$scope.filteredData=array;
});
$scope.getFiltered= function(obj, idx){
//Set a property on the item being repeated with its actual index
//return true only for every 1st item in 3 items
return !((obj._index = idx) % 5);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<body ng-app='app' ng-controller='appControl'>
<input type='text' ng-model='search' />
<table>
<tr ng-repeat="work in filteredData | filter:getFiltered | filter:search">
<td>{{work.Country}}</td>
<td ng-show="filteredData[work._index+1]">{{filteredData[work._index+1].Country}}</td>
<td ng-show="filteredData[work._index+2]">{{filteredData[work._index+2].Country}}</td>
<td ng-show="filteredData[work._index+3]">{{filteredData[work._index+3].Country}}</td>
<td ng-show="filteredData[work._index+4]">{{filteredData[work._index+4].Country}}</td>
</tr>
</table>
</body>
You could prefilter the items after a successful Ajax call and every time your model search changes.
Save the previously filtered items into $scope.workers.
Use $scope.$watch to watch for changes in the model search
Use the function searched(data) to filter for the entries that have characters given in the search field using the indexOf method. If the filter is empty, also show every item (typeof $scope.search == 'undefined').
If you want the search be case insensitive, transform searchand the Country .toLowerCase(), when using .indexOf()
Then you will only need one Angular filter $scope.getFiltered(), which makes sure, that the entries are in rows of five.
var test= angular.module("app", []);
test.controller("appControl", function($scope, $http) {
$http.get("http://www.w3schools.com/angular/customers.php")
.success(function (response) {
$scope.data = response.records;
$scope.workers = $scope.searched($scope.data);
}
);
$scope.getFiltered= function(obj, idx){
//Set a property on the item being repeated with its actual index
//return true only for every 1st item in 5 items
return !((obj._index = idx) % 5);
};
$scope.searched = function (data) {
var array = [];
var max = 0;
if (typeof data === 'object') {
max = data.length;
}
for (var i = 0; i < max; i += 1) {
if (typeof $scope.search == 'undefined' || data[i].Country.toLowerCase().indexOf($scope.search.toLowerCase()) != -1) {
array.push(data[i]);
}
}
return array;
};
$scope.$watch('search', function () {
$scope.workers = $scope.searched($scope.data);
})
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<body ng-app='app' ng-controller='appControl'>
<input type='text' ng-model='search' />
<table>
<tr ng-repeat="work in workers | filter:getFiltered">
<td>{{ work.Country }}</td>
<td>{{ workers[$index+1].Country }}</td>
<td>{{ workers[$index+2].Country }}</td>
<td>{{ workers[$index+3].Country }}</td>
<td>{{ workers[$index+4].Country }}</td>
</tr>
</table>
</body>

Categories