Navigate limitTo batches in Angular ngRepeat - javascript

I have an ngRepeat with a limitTo in my HTML. This will show the first x number of users - essentially paginating the table. I now need to be able to show the next batch of x users. I've added a couple of anchors to go to previous or next page (with functions attached to the click)
I'm now not sure how to manipulate the ngRepeat through these functions to actually show the correct batch of users.
HTML
<div ng-repeat="user in users | limitTo:paginate.size">
{{user.name}}
{{user.email}}
</div>
<ul class="pagination">
<li>left</li>
<li>right</li>
</ul>
JS
$scope.users = //full users object here
$scope.paginate = {};
$scope.paginate.size = 10;
$scope.prevPage = function(){
//load the previous 10 users
}
$scope.nextPage = function(){
//load the next 10 users
}

You should add another filter (or simply a custom filter) such as
<div ng-repeat="user in users | filter:getList(user, index)">
{{user.name}}
{{user.email}}
</div>
and then in the scope
$scope.users = //full users object here
$scope.paginate = {};
$scope.paginate.size = 10;
$scope.paginate.start = 0;
$scope.prevPage = function(){
//load the previous 10 users
if ($scope.paginate.start) {
$scope.paginate.start -= $scope.paginate.size;
}
}
$scope.nextPage = function(){
//load the next 10 users
$scope.paginate.start += $scope.paginate.size;
}
$scope.getList = function (user, index) {
return (index >= $scope.paginate.start && index < $scope.paginate.start + $scope.paginate.size);
};

Related

How to manage angularJS priority in Functions execution?

#Context
$scope.getAllEvents() is getting an array from Firebase database within the 10 last events and put it in the $scope.events array. Then the function is sorting by date $scope.events. I'm initializing $scope.spliceTab and calling $scope.spliceFunc().
$scope.counterPub() is triggered in HTML each time the ng-repeat $index is a multiple of 5. The function is storing in $scope.spliceTab each values of the $index which were triggered. Basically it's a tab where future new items locations are registered. Then i delete doubles and save results in $scope.result.
Finally, $scope.spliceFunc() is reading inside $scope.result, and insert into $scope.events new items where positions are stored into $scope.result.
#Running
At the start of my app, $scope.events is filled up but $scope.result from $scope.spliceFunc() stays empty. When I'm using the infinite scroll to load 10 more events, it is working but the $scope.events.sort() algorithm is working before $scope.spliceFunc(), so my new items are on the bottom of my list and not in the positions I want.
#Problem
I would like to run my app this way:
filled up $scope.events from Firebase
Sort $scope.events by date
ng-repeat in HTML and filled up $scope.spliceTab when triggered
Finally running $scope.spliceFunc() on the already sorted array $scope.events
What do you think, is this possible ?
// FUNCTION TO GET EVENTS
$scope.getAllEvents = function() {
if ($scope.listSiz === undefined) {
$scope.listSiz = 10;
}
var ref = firebase.database().ref().child("events");
$scope.events = $firebaseArray(ref.orderByChild('endDate').limitToFirst($scope.listSiz));
$scope.events.$loaded().then(function()
{
$scope.events.sort(function compareNumbers(y, x) {
var date1 = new Date(x.endDate);
var date2 = new Date(y.endDate);
return date1 - date2;
});
if ($scope.listSiz === 30) {
$scope.noMoreItemsAvailable = true;
}
$scope.spliceTab = [];
$scope.spliceFunc();
});
};
// FUNCTION TRIGGERED IN HTML
$scope.counterPub = function($index) {
var modulo = $index % 5;
if (modulo === 0) {
$scope.spliceTab.push($index);
// Delete doubles
$scope.result = [];
$scope.spliceTab.forEach(function(item) {
if ($scope.result.indexOf(item) < 0) {
$scope.result.push(item);
}
});
return true;
} else {
return false;
}
};
// FUNCTION SPLICE
$scope.spliceFunc = function() {
// console.log("************* TAB ****************** =", $scope.result);
angular.forEach($scope.result, function(value) {
$scope.events.splice(value, 0, [{
name: "toto"
}]);
});
};
<ion-view>
<ion-content>
<ion-list ng-controller="MCtrl">
<ion-item ng-repeat="e in events">
<!-- IF ADDS -->
<div ng-if="counterPub($index) === true">
Hello world !
</div>
<!-- -->
<div>
<img data-ng-src="{{ ::e.creatorAvatar }}">
</div>
</ion-item>
</ion-list>
</ion-content>
</ion-view>

Ionic scroll Performance issue

I am developing application in which I have feeds or some timeline. here is my ng-repeat code:
<div ng-repeat="x in feeds" class="fd-feed-card">
<div class="fd-feed-usr-img">
<img ng-src="{{x.user.media[0].small}}" class="fd-img fd-img-br border-style">
</div>
<div class="ft-16 fd-feed-usr-name">
<span><b>{{x.user.name}}</b></span><span class="ft-12 fd-feed-created-time plx prm">{{x.feed.createdTimeStamp | readableTime}}</span>
</div>
<div ng-style="imgStyle">
<img ng-src="{{x.feed.media[0].medium}}" class="fd-img objectcover image-blur">
</div>
<div ng-if="x.feed.total_comments > 0 || x.feed.total_likes >0">
<p class="mll"><span on-tap="openCommentModal(x.feed._id, $index, x.feed)" class="prm" ng-if="x.feed.total_comments > 0">{{x.feed.total_comments}} Comment</span><span ng-if="x.feed.total_likes>0" on-tap="openUserModal(x.feed._id)">{{x.feed.total_likes}} Likes</span>
</p>
</div>
<div class="fd-feed-distance">
<span class="plx prm ft-16">{{x.distance}} <span class="ft-10">mil</span></span>
</div>
</div>
here every feed contains username, userimage and 400*400px image of feed and distance. after this im using ionic infinite scroll like this:
<ion-infinite-scroll on-infinite="getDashboardFeed()" distance="1%" ng-if="!noMoreFeedContent"></ion-infinite-scroll>
in my javascript code, i am calling API with pagination having 5 feeds at a time. here it is my javascript code:
$scope.getDashboardFeed = function(start) {
var _start = start || false;
var params = {}
params.offset = offset;
params.limit = limit;
Posts.getAllFeeds(params).success(function(res) {
if (_start) {
$scope.feeds = [];
}
if (res.data.length < limit) {
$scope.noMoreFeedContent = true;
} else {
$scope.noMoreFeedContent = false;
}
for (var i = 0; i < res.data.length; i++) {
var markerPos = new google.maps.LatLng(res.data[i].feed.location[0], res.data[i].feed.location[1]);
var currentLatLng = new google.maps.LatLng(res.data[i].location.location[0], res.data[i].location.location[1])
var distance = google.maps.geometry.spherical.computeDistanceBetween(markerPos, currentLatLng) * 0.000621371;
res.data[i].distance = distance.toFixed(2);
for (var j = 0; j < res.data[i].feed.likes.length; j++) {
if (uid == res.data[i].feed.likes[j].user) {
res.data[i].isLiked = true;
break;
} else {
res.data[i].isLiked = false;
}
}
$scope.feeds.push(res.data[i]);
}
offset = offset + limit;
if (_start) {
$scope.$broadcast('scroll.refreshComplete');
} else {
$scope.$broadcast('scroll.infiniteScrollComplete');
}
})
.error(function(err) {
})
};
im also calculating distance of every feed based on current location. and checking if i liked the post or not.
Now the problem is when feed is loaded to 25,30 , the scroll becomes laggy in my android . Im also using native scrolling given in this link ,
i have read also more blogs like this
but i didnt get much help. I have to load 1000s of feeds here where every feed contains 400*400px picture.
i also tried collection-repeat. it didnot work either.
Is there any other approach I can try to fix my scroll perfomance?
Anybody can help me with that?
I had same issue, especially when using images in ng-repeat.
Check out my answer here

Moving objects between two arrays

I have two lists formed from an array containing objects.
I'm trying to move objects from one list to the other and vice versa.
Controller:
spApp.controller('userCtrl',
function userCtrl($scope,userService,groupService){
//Generate list of all users on the SiteCollection
$scope.users = userService.getUsers();
//array of objects selected through the dom
$scope.selectedAvailableGroups;
$scope.selectedAssignedGroups;
//array of objects the user actually belongs to
$scope.availableGroups;
$scope.assignedGroups;
//Generate all groups on the site
$scope.groups = groupService.getGroups();
//Boolean used to disable add/remove buttons
$scope.selectedUser = false;
//Take the selectedAvailableGroups, add user to those groups
//so push objects to "assignedGroups" array and remove from "avaiableGroups" array
$scope.addUserToGroup = function (){
userService.addUserToGroup($scope.selectedUser, $scope.selectedAvailableGroups, $scope.assignedGroups, $scope.availableGroups)
};
}
);
Service:
spApp.factory('userService', function(){
var addUserToGroup = function (selectedUser, selectedAvailableGroups, assignedGroups, availableGroups) {
var addPromise = [];
var selectLength = selectedAvailableGroups.length;
//Add user to selected groups on server
for (var i = 0; i < selectLength; i++) {
addPromise[i] = $().SPServices({
operation: "AddUserToGroup",
groupName: selectedAvailableGroups[i].name,
userLoginName: selectedUser.domain
});
};
//when all users added, update dom
$.when.apply($,addPromise).done(function (){
for (var i = 0; i < selectLength; i++) {
assignedGroups.push(selectedAvailableGroups[i]);
availableGroups.pop(selectedAvailableGroups[i]);
};
//alert(selectedUser.name + " added to: " + JSON.stringify(selectedAvailableGroups));
});
}
}
Object:
[{
id: 85,
name: Dev,
Description:,
owner: 70,
OwnerIsUser: True
}]
HTML:
<div>
<label for="entityAvailable">Available Groups</label>
<select id="entityAvailable" multiple
ng-model="selectedAvailableGroups"
ng-options="g.name for g in availableGroups | orderBy:'name'">
</select>
</div>
<div id="moveButtons" >
<button type="button" ng-disabled="!selectedUser" ng-click="addUserToGroup()">Add User</button>
<button type="button" ng-disabled="!selectedUser" ng-click="removeUserFromGroup()">Remove</button>
</div>
<div>
<label for="entityAssigned">Assigned Groups</label>
<select id="entityAssigned" multiple
ng-model="selectedAssignedGroups"
ng-options="g.name for g in assignedGroups | orderBy:'name'">
</select>
</div>
Right now, the push into assigned groups works but only updates when I click on something else or in the list, not really dynamically. But the biggest issue is the .pop() which I don't think works as intended.
$.when.apply($,addPromise).done() seems not to be angular api or synchronous. So angular is not aware of your changes. You must wrap your code inside a $scope.$apply call:
$scope.$apply(function(){
for (var i = 0; i < selectLength; i++) {
assignedGroups.push(selectedAvailableGroups[i]);
availableGroups.pop(selectedAvailableGroups[i]);
};
});
If you click on something, a $digest loop will happen and you will see your changes.
Your pop did not work because Array.pop only removes the last element. I guess that is not what you want. If you want to remove a specific element you should use Array.splice(),

$scope not filtering with other parts of controller in AngularJS

I have a controller that is pretty much an exact copy of the demo from AngularJS. I wanted to add a function to grab some items from an array within the items.
The issue I am running into is that the results are not filtering along with the main part of the controller.
Here is the original part of the controller.
function EmployerListCtrl($scope, Employer) {
$scope.employers = Employer.query();
$scope.orderProp = 'age';
$scope.getEmployerCount = function () {
return $scope.employers.length;
};
I added this function.
$scope.getSkillsList = function () {
var employerArray = this.employers;
var skillsArray = new Array();
for (var i = 0; i < employerArray.length; i++) {
if (employerArray[i].software != undefined || employerArray[i].software != null) {
for (var j = 0; j < employerArray[i].software.length; j++) {
skillsArray.push(employerArray[i].software[j]);
}
}
}
return skillsArray;
};
I also tried to use the same $scope as the main part of the controller, however it also shows just the initial results.
$scope.getSkillsList2 = function () {
var employerArray = $scope.employers;
var skillsArray = new Array();
for (var i = 0; i < employerArray.length; i++) {
if (employerArray[i].software != undefined || employerArray[i].software != null) {
for (var j = 0; j < employerArray[i].software.length; j++) {
skillsArray.push(employerArray[i].software[j]);
}
}
}
return skillsArray;
};
Here is the contents of the HTML Page. The ng-model="query" is what I am using to filter the ng-repeat.
<div class="container-fluid">
<p>Set One: {{getSkillsList()}}</p>
<p>Set Two: {{getSkillsList2()}}</p>
<div class="row-fluid">
<div class="span2">
<!--Sidebar content-->
Search: <input ng-model="query">
Sort by:
<select ng-model="orderProp">
<option value="name">Alphabetical</option>
<option value="age">Newest</option>
</select>
<p>Number of employers in list: {{getEmployerCount()}}</p>
</div>
<div class="span10">
<!--Body content-->
<ul class="employers">
<li ng-repeat="employer in employers | filter:query | orderBy:orderProp" class="thumbnail">
<img ng-src="{{employer.imageUrl}}">
{{employer.name}}
<p>{{employer.snippet}}</p>
</li>
</ul>
</div>
</div>
</div>
I think you are hoping to have the skillsArray automatically shrink or grow based on the ng-repeat filter. That won't work. In this line:
<li ng-repeat="employer in employers | filter:query | orderBy:orderProp" ...>
the results of the filter are not seen by the parent scope, but only by the ng-repeat scopes. In other words, the filter does not alter $scope.employers, so your skills functions will continue to operate on the full employers array received from the server.
One way to accomplish what you want is to define your own filter function, then chain it with the query filter one:
angular.module('myApp', []).
filter('skills', function() {
return function(filteredEmployers) {
var skillsArray = [];
... do your filtering here ...
return skillsArray;
}
});
Then in your HTML:
<li ng-repeat="skills in employers | filter:query | skills">
{{skill}}
</li>
See also Creating Angular Filters.

AngularJS: Hitting a strange issue with $scope variables

In the following code, whenever you delete an item from the delete link in the list, it will only delete the item from the list, but it will not delete the currently selected item. (The item displaying once you click on it). However, if you click on the delete link next to the currently selected item, it will delete from both places.
To replicate what I'm seeing:
Add a bunch of items by typing in the text box and hitting enter a few times.
Select one of the items from the list.
Click delete next to the item when it displays below.
This is the correct behavior.
Select another item you created earlier.
Now click the delete link next to the item in the list.
The item is removed from the list, but not the currently displayed item.
When I step into the code $scope.currentUser is undefined when I click on the delete link in the list.
Why is this happening?
<html ng-app="myApp">
<head>
<script src="http://code.angularjs.org/1.0.1/angular-1.0.1.min.js"></script>
<script>
var app = angular.module('myApp', []);
app.config(function($routeProvider) {
$routeProvider.when('/User/:id', {
controller: UserCtrl,
template: '<h1>{{currentUser.name}}</h1> <a ng-click="deleteUser(currentUser.id)">delete me</a>'
});
});
app.factory('userSvc', function(){
return new UserService();
});
function UserCtrl($scope, $routeParams, $location, userSvc) {
var currUser = userSvc.getUser($routeParams.id);
$scope.currentUser = currUser;
$scope.users = userSvc.getAllUsers();
$scope.addUser = function () {
var user = {
id: userSvc.nextId(),
name: $scope.addUserName
};
userSvc.addUser(user);
$scope.addUserName = '';
$location.url('/User/' + user.id);
};
$scope.deleteUser = function(id) {
if($scope.currentUser != null && $scope.currentUser.id == id) {
$scope.currentUser = null;
}
userSvc.delete(id);
};
};
function UserService() {
var users = [{id: 1, name: 'Ben' }];
this.delete = function(id) {
for(var i = 0; i < users.length; i++) {
var user = users[i];
if(user.id == id) {
users.splice(i,1);
}
}
};
this.addUser = function(user) {
users.push(user);
};
this.getAllUsers = function() {
return users;
};
this.getUser = function(id) {
for(var i = 0; i < users.length; i++) {
var user = users[i];
if(user.id == id) {
return user;
}
}
};
this.nextId = function() {
var maxId = 0;
for(var i = 0; i < users.length; i++) {
var user = users[i];
maxId = Math.max(maxId, user.id);
};
return maxId + 1;
};
}
</script>
</head>
<body>
<div ng-controller="UserCtrl">
<form ng-submit="addUser()">
<input ng-model="addUserName" type="text"/>
<input type="submit" value="Add"/>
</form>
<ul>
<li ng-repeat="user in users">{{user.name}} <a ng-click="deleteUser(user.id)">delete</a></li>
</ul>
</div>
<div ng-view></div>
</body>
</html>
It turns out that selecting a user from the list actually also created a brand new scope that was seperate from the one used to bind the list.
Thanks to Gloopy's comment above to check out Batarang, I was able to see this happen. If this happens to help you, please +1 his comment.
According to the documentation on Scopes some directives will actually cause a new scope to be created. I'm assuming that clicking a link that is being handled by the $routeProvider also results in the creation of a whole new scope tree, likely because it's creating another instance of that controllor.

Categories

Resources