Filtering from to letter in Angular - angularjs

I have been through a few of those questions on Stackoverflow and found this link from a thread:http://toddmotto.com/everything-about-custom-filters-in-angular-js/ which is great but I am struggling to adapt it to what I need to do.
I am trying to implement a simple function based on it which will have a button group one which shows all results then from and to letter such as:
<button type="button" class="btn btn-primary">All</button>
<button type="button" class="btn btn-primary”>A-E</button>
<button type="button" class="btn btn-primary">F-K</button>
<button type="button" class="btn btn-primary">L-P</button>
However I am unable to adapt the function to perform this filter. I can only do with the basic filter by single letter.
<button type="button" class="btn btn-primary" ng-click="letter = 'C'">C</button>
I am also unable to show “all results"
Here is my app code:
var app = angular.module (‘app', []);
app.controller('PersonCtrl', function () {
this.friends = [{
name: 'Andrew'
},
{
name: 'Bob'
},{
name: 'Beano'
},{
name: 'Chris'
}, {
name: 'Will'
}, {
name: 'Mark'
}, {
name: 'Alice'
}, {
name: 'Todd'
}];
});
app.filter('startsWithLetter', function () {
return function (items, letter) {
var filtered = [];
var letterMatch = new RegExp(letter, 'i');
for (var i = 0; i < items.length; i++) {
var item = items[i];
if (letterMatch.test(item.name.substring(0, 1))) {
filtered.push(item);
}
}
return filtered;
};
});
HTML CONTROLLER CODE:
<div class="container" ng-controller="PersonCtrl as person">
<ul>
<li ng-repeat="friend in person.friends | startsWithLetter:letter">
{{ friend }}
</li>
</ul>
</div>
How do I adapt this to perform more specific filtering?

You can use colons to pass multiple arguments to your filter - fromLetter and toLetter as well as your input.
<li ng-repeat="friend in person.friends | startsWithLetter:person.fromLetter:person.toLetter">
{{ friend }}
</li>
Then you can lowercase the first letter of the string and compare this directly to fromLetter and toLetter
app.filter('startsWithLetter', function () {
return function (items, fromLetter, toLetter) {
var filtered = [];
for (var i = 0; i < items.length; i++) {
var item = items[i];
var firstLetter = item.name.substring(0, 1).toLowerCase();
if ((!fromLetter || firstLetter >= fromLetter)
&& (!toLetter || firstLetter <= toLetter)) {
filtered.push(item);
}
}
return filtered;
};
});
That means that the button logic needs to be slightly more complex and set two variables:
<button type="button" class="btn btn-primary" ng-click="person.setLetters()">All</button>
<button type="button" class="btn btn-primary" ng-click="person.setLetters('a','e')">A-E</button>
<button type="button" class="btn btn-primary" ng-click="person.setLetters('f','k')">F-K</button>
<button type="button" class="btn btn-primary" ng-click="person.setLetters('l','p')">L-P</button>
and on your controller:
this.setLetters = function(from, to){
this.fromLetter = from;
this.toLetter = to;
};
JSFiddle

You could have filtering based on the alphabet ASCII codes. On button click set the range of ASCII code using ng-click directive with - separated value like letter='65-69. Then that range will pass through the the filter, out of which first parameter is upperLimit & 2nd one is lowerLimit of the selected range. For comparing the starting variable ASCII value we could use string.charCodeAt('0') method which will return ASCII value of first character & will compare that value with the range variable inside foreach loop.
Markup
<div class="container" ng-controller="PersonCtrl as person">
<ul>
<li ng-repeat="friend in person.friends | startsWithLetter:letter">
{{ friend }}
</li>
</ul>
<button type="button" class="btn btn-primary" ng-click="letter=''">All</button>
<button type="button" class="btn btn-primary" ng-click="letter='65-69'">A-E</button>
<button type=" button " class="btn btn-primary" ng-click="letter='70-75'">F-K</button>
<button type="button " class="btn btn-primary " ng-click="letter='76-80'">L-P</button>
</div>
Filter
app.filter('startsWithLetter', function() {
return function(items, letter) {
if (!letter || letter.length == 0)
return items;
var filtered = [],
range = letter.split('-');
var letterMatch = new RegExp(letter, 'i');
for (var i = 0; i < items.length; i++) {
var item = items[i];
for (var j = parseInt(range[0]); j <= parseInt(range[1]); j++) {
if (item.name.charCodeAt('0') == j) {
filtered.push(item);
}
}
}
return filtered;
};
});
Working PLunkr

Related

AngularJS table flickers

I have a simple AngularJS app that shows a table with data on an ng-repeat after the user logins. I'm having an issue where after logging in, the table briefly shows blank rows and then the actual rows with data. Any suggestions on how to fix this?
This is the controller for the login:
$scope.login = function(user) {
loginSrvc.login(user).then(function(response) {
if (response == "authentication failed") {
$scope.error = true;
$scope.user = {};
$location.path("/");
} else {
if (response.group_name == "On Site Registration"){
var data = {
event: response.zk_event_id,
group: response.zk_group_id
};
$scope.getAvailableCamper(data);
}
else if (!response.zk_group_id) {
$location.path("/form/" + response.zkp_camper_id);
}
else {
$location.path("/dashboard/" + response.zk_event_id + "/" + response.zk_group_id);
}
}
})
}
$scope.getAvailableCamper = function(data) {
dashboardSrvc.fetchGroup(data).then(function(response){
var findAvailableCamper = _.find(response.data, {status: null});
console.log("this is find", findAvailableCamper);
var id = findAvailableCamper.zkp_camper_id;
$location.path("/onSiteForm/" + id);
})
}
This is the controller for the table:
$scope.campers = function() {
$scope.camper = loginSrvc.getCampers();
}
$scope.campers();
$scope.fetchCampers = function(id) {
dashboardSrvc.fetchCampers(id).then(function(response){
$location.path("/form/" + id);
})
}
Here's the html code for table:
<tr ng-repeat="campers in camper">
<td>{{$index + 1}}</td>
<td>{{campers.name_first}}</td>
<td>{{campers.name_last}}</td>
<td><button type="submit" name="submit" ng-click="register(campers)" class="btn btn-success" role="button" ng-hide="campers.status == 'Submitted' " ng-disabled="!(!!campers.name_first && !!campers.name_last && !!campers.gender && !!campers.city && !!campers.date_of_birth && !!campers.email && !!campers.emergency_cell_phone && !!campers.emergency_contact_first_name && !!campers.emergency_contact_last_name && !!campers.emergency_home_phone && !!campers.relationship_to_camper && !!campers.first_time_flag )">Submit</button> <p ng-show ="campers.status == 'Submitted'" > {{campers.registration_date | date: 'medium'}}
</p>
</td>
<td>{{campers.status}}</td>
<td>
<button ng-click="fetchCampers(campers.zkp_camper_id)" type="submit" name="view" class="btn btn-default" role="button" ng-show="campers.status == 'Submitted' "><span class="glyphicon glyphicon-eye-open"></span></button>
<button ng-click="fetchCampers(campers.zkp_camper_id)" type="submit" name="edit" class="btn btn-default" role="button" ng-hide="campers.status == 'Submitted' " ><span class="glyphicon glyphicon-edit"></span></button>
<button type="button" ng-click="setValue(campers.zkp_camper_id)" name="deleteModalLauncher" id="deleteModalLauncher" class="btn btn-danger" role="button" data-toggle="modal" data-target="#deleteModal" ng-hide="campers.status == 'Submitted' " ><span class="glyphicon glyphicon-trash" aria-hidden="true"></span></button>
</td>
</tr>
I really appreciate the help! Thanks!
There is a directive to minimize flickering that angular loop does while check bindings and all. it is called ng-cloak and it can be added to any element on your view.
More info : https://www.w3schools.com/angular/ng_ng-cloak.asp
...
You can also use angularjs event who is fired when content is fully loaded and set a flag ex. loaded = true and then use ng-show with loaded variable.
Controller :
$scope.$on('$viewContentLoaded', function(){
$scope.loaded = true;
});
View :
<table ng-show="loaded">
.....
</table>
Hope that helps!

how to refresh the list in AngularJs?

I have to implement the share product functionality with the user after share i have to refresh the list here selectedSharedIntermediaryInAlbum is our array so how to implement this?
//refreshSharedIntermediary for refresh the lsit
$scope.refreshSharedIntermediary = function() {
$scope.selectedSharedIntermediaryInAlbum = $scope.selectedSharedIntermediaryInAlbum;
}
<div class="w3-right">
<button class="btn btn-rose btn-sm" tltle="refresh data" ng-click="refreshSharedIntermediary()">
<i class="glyphicon glyphicon-repeat"></i>
</button>
</div>
You can use $scope.reload function where need to reload the list ... i have used below concept :
<div class="well well-lg" ng-repeat="item in list track by item.id">
<button class="btn btn-default"
ng-click="collapsedFlags[item.id] = !collapsedFlags[item.id]">
{{ item.isCollapsed ? '+' : '-' }}
</button>
<div uib-collapse="collapsedFlags[item.id]" ng-bind="item.value"></div>
</div>
$scope.reload = function () {
$http.get('list.json').then(function (data) {
$scope.list = data && data.data || [];
});
};
$scope.collapsedFlags = {};
$scope.reload();
Working example : https://plnkr.co/edit/87vVb8Jjyz6yFGAjiHBK?p=preview

How to pass the values of a list as arguments of function in angularjs

HTML code
In the second controller when I am trying to show the values in "itemBought List" on click of button its rendering empty string for name and quantity while I have data for the same in itemToBuy.itemList".
It seems the datas for name and quantity are not passed into the addItemToBoughtList() function. How to achieve that.
<!-- To Buy List -->
<div class="col-md-6" ng-controller="ToBuyController as itemToBuy">
<h2>To Buy:</h2>
<ul>
<li ng-repeat="item in itemToBuy.itemList"> Buy {{item.itemQuantity}} of {{item.itemName}}
<button class="btn btn-default" ng-click="itemToBuy.addItemToBoughtList()"><span class="glyphicon glyphicon-ok"></span> Bought</button></li>
</ul>
<div class="emptyMessage">Everything is bought!</div>
</div>
<!-- Already Bought List -->
<div class="col-md-6" ng-controller="AlreadyBoughtController as itemBought">
<h2>Already Bought:</h2>
<ul>
<li ng-repeat="item in itemBought.items">
Bought {{ items.quantity }} of {{ item.name }}</li>
</ul>
<div class="emptyMessage">Nothing bought yet.</div>
</div>
</div>
Javascript code
(function (){
'use strict';
angular.module('ShoppingListCheckOff', [])
.controller('ToBuyController', ToBuyController)
.controller('AlreadyBoughtController', AlreadyBoughtController)
.service('ShoppingListCheckOffService',ShoppingListCheckOffService);
ToBuyController.$inject = ['ShoppingListCheckOffService'];
function ToBuyController(ShoppingListCheckOffService) {
var itemToBuy= this;
itemToBuy.itemName = "";
itemToBuy.itemQuantity = "";
itemToBuy.itemList = [
{itemName : 'cookies', itemQuantity : 10},
{itemName : 'napkins', itemQuantity : 15}
];
itemToBuy.addItemToBoughtList = function () {
ShoppingListCheckOffService.addItemToBoughtList(itemToBuy.itemName, itemToBuy.itemQuantity);
}
}
AlreadyBoughtController.$inject = ['ShoppingListCheckOffService'];
function AlreadyBoughtController(ShoppingListCheckOffService) {
var itemBought = this;
itemBought.name="";
itemBought.items = ShoppingListCheckOffService.getItems();
}
function ShoppingListCheckOffService() {
var service = this;
// List of shopping items
var items = [];
service.addItemToBoughtList = function (itemName, quantity) {
var item = {
name: itemName,
quantity: quantity
};
items.push(item);
};
service.getItems = function ()
return items;
};
}
})();
Pass Item to your addItemToBoughtList function
<ul>
<li ng-repeat="item in itemToBuy.itemList"> Buy {{item.itemQuantity}} of {{item.itemName}}
<button class="btn btn-default" ng-click="itemToBuy.addItemToBoughtList(item)"><span class="glyphicon glyphicon-ok"></span> Bought</button></li>
</ul>
and receive it in your function in js
itemToBuy.addItemToBoughtList = function (item) {
ShoppingListCheckOffService.addItemToBoughtList(item.itemName, item.itemQuantity);
}
I have created a plunker with your code. It is working fine, have a look

$watchGroup in angularjs is not working

I am using ng-repeat to show items of objects in array, im using also filter with pagination.
in the below im using $watch to watch Filter.type.car and its work fine , but when i tried to watch Filter.type.car and Filter.type.Motorbike together using $watchGroup as below its now working.
$scope.currentPage = 0;
$scope.pageSize = 10;
$scope.getData = function () {
return $filter('filter')($scope.vichicles);
};
$scope.numberOfPages=function(){
return Math.ceil($scope.vichicles/$scope.pageSize);
};
$scope.$watchGroup(['Filter.type.car','Filter.type.motorbike'], function(term){
$scope.filtered = filterFilter($scope.vichicles, term);
$scope.getData = function () {
return $filter('filter')($scope.filtered)
};
$scope.numberOfPages=function(){
return Math.ceil($scope.getData().length/$scope.pageSize);
};
$scope.totalItems = $scope.filtered.length;
});
and this is the view
<div class="pagination">
<div class="pager">
<span class="current-page">{{currentPage+1}}</span>
<span class="total-pages">{{numberOfPages()}}</span>
</div>
<span class="total-items">{{totalItems}}</span>
<span class="item-description">Vichicles</span>
<button class="btn btn-clear arrow arrow-up" ng-disabled="currentPage == 0" ng-click="currentPage=currentPage-1">Previous</button>
<button class="btn btn-clear arrow arrow-down" ng-disabled="currentPage >= getData().length/pageSize - 1" ng-click="currentPage=currentPage+1">Next</button>
</div>
<ul class="list">
<li ng-repeat="v in vichicles | filter: search |searchFilter:Filter.type | searchFilter:Filter.level| startFrom:currentPage*pageSize | limitTo:pageSize">
Use separate Watch instead of watchGroup since those are not array
$scope.$watch('Filter.type.car', function() {
alert('hey, car has changed!');
});
$scope.$watch('Filter.type.motorbike', function() {
alert('hey, bike has changed!');
});

Onclick Button Change AngularUI

I'm trying to make 6 buttons that are selectable. I'm having trouble adding more than two. The third button is selecting other buttons and also the buttons are deselecting themselves when clicked twice. Which is undesired. It's a mess. Can anyone help me sort this out?
Here's my code:
<div ng-app="plunker">
<div ng-controller="MainCtrl">
<button type="button" class="btn" ng-class="{'btn-primary':isUploadActive}" ng-click="toggleActive1()">Upload</button>
<button type="button" class="btn" ng-class="{'btn-primary':isDownloadActive}" ng-click="toggleActive2()">Download</button>
</div>
</div>
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.button1Active = false;
$scope.button2Active = false;
$scope.button3Active = false;
$scope.button4Active = false;
$scope.button5Active = false;
$scope.button6Active = false;
$scope.toggleActive1 = function() {
if($scope.button2Active) {
$scope.button2Active = !$scope.button2Active;
}
$scope.button1Active = !$scope.button1Active;
};
$scope.toggleActive2 = function() {
if($scope.button1Active) {
$scope.button1Active = !$scope.button1Active;
}
$scope.button2Active = !$scope.button2Active;
};
$scope.toggleActive3 = function() {
if($scope.button3Active) {
$scope.button3Active = $scope.button3Active;
}
$scope.button2Active = !$scope.button2Active;
$scope.button1Active = !$scope.button1Active;
$scope.button4Active = !$scope.button4Active;
$scope.button5Active = !$scope.button5Active;
$scope.button6Active = !$scope.button6Active;
};
});
<div id="contentDiv">
<div ng-app="plunker">
<div ng-controller="MainCtrl">
<button type="button" class="btn" ng-class="{'btn-primary':button1Active}" ng-click="toggleActive1()">Upload</button>
<button type="button" class="btn" ng-class="{'btn-primary':button2Active}" ng-click="toggleActive2()">Download</button>
<button type="button" class="btn" ng-class="{'btn-primary':button3Active}" ng-click="toggleActive3()">Purchased</button>
</div>
</div>
Yikes! that is a bit messy. I made a fiddle that seems to do what you want: http://jsfiddle.net/qwah3/
Basically I just give the controller one scoped object that holds the active button, and each button just checks against that value:
function myCtrl($scope) {
$scope.active = { val : '' };
$scope.Activate = function(buttonVal) {
$scope.active.val = buttonVal;
};
}
That means each button can just be like this:
<button type="button" class="btn" ng-class="{'btn-primary':active.val == 'Download'}"
ng-click="Activate('Download')">Download</button>
You could even turn the button into a directive to make it even easier.
Hope this helped!

Resources