Progressive scrolling with angularjs - angularjs

I have a database witch contains 1000 products. I have a list which displays 10 products at one time. This grid is scrollable. I want to load products 10 by 10.
What is the best way to do this with angularjs ? I am looking for a method which need shortest code.
Thanks

The concept is called pagination and if you want to achieve this in less amount of time then you must go for any already available module.
I have used Infinite Scroll It is very easy to use and would help you to implement things in no time.

You are looking for lib called "infinite scroll". You can find this app here https://github.com/ifwe/infinite-scroll
Where in the controller you put this code:
var app = angular.module('MyApp', ['tagged.directives.infiniteScroll']);
app.controller('MainController', ['$scope', '$http', function($scope, $http) {
$scope.page = 1;
$scope.items = [];
$scope.fetching = false;
// Fetch more items
$scope.getMore = function() {
$scope.page++;
$scope.fetching = true;
$http.get('/my/endpoint', { page : $scope.page }).then(function(items) {
$scope.fetching = false;
// Append the items to the list
$scope.items = $scope.items.concat(items);
});
};
}]);
And this is your view:
<div ng-app="MyApp">
<div ng-controller="MainController">
<ul tagged-infinite-scroll="getMore()">
<li ng-repeat="item in items">
{{ item.title }}
</li>
</ul>
</div>
</div>
Once it detect you scroll is at the end of the ng-repeat items it calls getMore function to load new items. Remember to add to the endpoint limit, and offset to load rest of the data, not same data every time.

Related

IONIC: unable to load dynamic content in `ion-infinite-scroll`

I am new with ionic framework.Currently i am working on ionicsidemenu app.
I have 100 plus records i want to display 20 records at once. When scroll down get next 20 records. For this i am using ion-infinite-scroll but i am unable to understand how to call next 20 records. I am using webservice for fetching records.
Please help me.
You have to use array instead of object in this case because pushing items in array is easier than pushing into object. Ionic documentaton also uses array in their example.
View:
<div ng-repeat="item in data">...</div>
<ion-infinite-scroll (ionInfinite)="getData()">
<ion-infinite-scroll-content></ion-infinite-scroll-content>
</ion-infinite-scroll>
Controller:
$scope.data = [];
var page = 1;
$scope.getData = function(){
$http.get('http://example.com?page='+page).then(function(response){
page++;
$.each(response,function(key,item){
$scope.data.push(item);
});
}, function(error){
});
}
When scroll reach to ion-infinite-scroll function will called. at beginning there is no data on screen so without scrolling ion-infinite-scroll function called automatically to load first page.
use limitTo together with Infinite scrolling. AngularJS ng-repeat offers from version 1.1.4 the limitTo option. I slightly adapted the Infinite Scroll directive to make scrolling within a container possible that does not have height 100% of window.
ng-repeat="item in items | orderBy:prop | filter:query | limitTo:limit"
Notice that limit is a variable in the $scope, so changing it automatically adjusts the number of rendered items. And incrementing limit, only renders the added elements.
<table>
<tr ng-repeat="d in data | limitTo:totalDisplayed"><td>{{d}}</td></tr>
</table>
<button class="btn" ng-click="loadMore()">Load more</button>
//the controller
$scope.totalDisplayed = 20;
$scope.loadMore = function () {
$scope.totalDisplayed += 20;
};
$scope.data = data;
or try out this solution
<body>
<pane ng-controller="MainCtrl">
<header-bar title="'Infinite Scroll Example'">
</header-bar>
<content has-header="true" padding="true" on-infinite-scroll="addMoreItem">
<div class=" list padding">
<div ng-repeat="item in items | limitTo:numberOfItemsToDisplay" class="item" type="item-text-wrap">
<h3>{{item}}</h3>
</div>
</div>
</content>
</pane>
</body>
js code
angular.module('myApp', ['ionic'])
.controller('MainCtrl', function($scope) {
$scope.numberOfItemsToDisplay = 20; // number of item to load each time
$scope.items = getData();
function getData() {
var a = [];
for (var i=1; i< 1000; i++) {
a.push(i);
}
return a;
}
$scope.addMoreItem = function(done) {
if ($scope.items.length > $scope.numberOfItemsToDisplay)
$scope.numberOfItemsToDisplay += 20; // load 20 more items
done(); // need to call this when finish loading more data
}
});
while on scrolling will display 20 items.

ng-repeat is not refreshed when ng-click method called from directive

I am working on creating reusable directive which will be showing composite hierarchical data .
On first page load, Categories like "Server" / "Software"/ "Motherboard" (items array bound to ng-repeat) would be displayed . If user clicks on "Server" then it would show available servers like "Ser1"/"Ser2"/"Ser3".
html :
<div ng-app="myApp" ng-controller="myCtrl" ng-init="init()">
<ul>
<li ng-repeat="item in items">
<div my-dir paramitem="item"></div>
</li>
</ul>
</div>
Now first time Items are loading, but clicking on any item is not refreshing ng-repeat. I have checked ng-click, "subItemClick" in below controller, method and it is being fired. However the items collection is not getting refreshed.
http://plnkr.co/edit/rZk9cbEJU90oupVgcSQt
Controller:
var myApp = angular.module('myApp', []);
myApp.controller('myCtrl', ['$scope', function($scope) {
$scope.init = function() {
$scope.items = [{iname: 'server',subItems: ['ser1', 'ser2','ser3']}
];
};
$scope.subItemClick = function(sb) {
if (sb.subItems.length > 0) {
var zdupitems = [];
for (var i = 0; i < sb.subItems.length; i++) {
zdupitems.push({
iname: sb.subItems[i],
subItems: []
});
}
$scope.items = zdupitems;
}
};
}])
.directive('myDir', function() {
return {
controller: 'myCtrl',
template: "<div><a href=# ng-click='subItemClick(paramitem)'>{{paramitem.iname}}</a></div>",
scope: {
paramitem: '='
}
}
});
I am expecting items like ser1/ser2 to be bound to ng-repeat on clicking "Server" but it is not happening .
Any help?
I think that onClick is screwing up the method's definition of $scope. In that context, the $scope that renders the ngRepeat is actually $scope.$parent (do not use $scope.$parent), and you're creating a new items array on the wrong $scope.
I realize the jsfiddle is probably a dumbed down example of what you're dealing with, but it's the wrong approach either way. If you need to use a global value, you should be getting it from an injected Service so that if one component resets a value that new value is reflected everywhere. Or you could just not put that onClick element in a separate Directive. What's the value in that?

Dynamically inserting elements in Angular JS

I have three tabs(Article(s), Visitor(s), Subscription(s)) and a common place of pagination; where each tab data will be provided with pagination. On click of the respective tab; respective ng-view are coming to picture and controllers are responding properly. For this custom made pagination; i want to update the number if <li> accordingly on the basis of the server response(number of pages available for next pagination).
<div ng-app="myLibrary">
<ul>
<li>Article(s)</li>
<li>Visitor(s)</li>
<li>Subscription(s)</li>
<li>
<ul> //will behave as pagination toolbar and each <li> represents a page; after a minimum of 5 pages; i will add a combo(as in plan) to cater more page(s)
<li ng-repeat="tPageObj in recordPageNumbers">
<span ng-click="fetchPage(tPageObj.pageIndex)">{{ tPageObj.pageIndex }}</span>
</li>
</ul>
</li>
</ul>
</div>
<div ng-view></div>
When the view is rendered(after getting the data from server; i have a array with the $scope ($scope.recordPageNumbers) and calculating the page(s) accordingly. Even in the console; it shows appropriate number of page(s); but i am unable to figure-out why the ng-repeat is not behaving(as i learned so-far; being two way binding modification in the model will trigar the view update) as it should.
var myLibrary = angular.module('myLibrary', ['ngRoute', 'ngTable']);
myLibrary.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/',
{ templateUrl : 'angular-view/article.html', controller : 'articleList' } );
$routeProvider.when('/articleManager',
{ templateUrl : 'angular-view/article.html', controller : 'articleList' } );
$routeProvider.when('/visitorManager',
{ templateUrl : 'angular-view/visitor.html', controller : 'visitorList' } );
$routeProvider.when('/subscriptionsManager',
{ templateUrl : 'angular-view/subscriptions.html', controller : 'subscriptions' } );
}]);
myLibrary.controller('articleList', function($scope, $http){
$scope.articleListArray = [];
$scope.recordPageNumbers = [];
$http.get('ngMyLibrary.do?action=ALLARTICLE')
.success(function(response) {
$scope.articleListArray = response.data; //sending data to `ng-view`
var totalPageCount = response.totalPageCount;//calculating pages and according creating the `recordPageNumbers` array.
if(totalPageCount){
for(var counter = 1; counter <= totalPageCount; counter++)
$scope.recordPageNumbers.push({pageIndex : counter, disableButton : false});
} else {
$scope.recordPageNumbers.push({pageIndex : 1, disableButton : true});
}
console.log($scope.recordPageNumbers); //console show as expected
}
);
});
Console:
[Object { pageIndex=1}, Object { pageIndex=2}, Object { pageIndex=3}, Object { pageIndex=4}, Object { pageIndex=5}, Object { pageIndex=6}]
I tried with {{ $index }} as the loop index of the ng-repeat but it din't work as well. Please help. I am newbie to ng; hence could not figure out the way to check within the ng-repat tag through debug.
Without seeing the full project structure it is a bit difficult to know. But have you checked to see if the controllers scope covers the HTML you are trying to use?
For example update the first line to be
<div ng-app="myLibrary" ng-controller="articleList">
It could be that the way you have it set up with the routing, the controller is only being responsible for the HTML being injected into the ng-view part of the page.

AngularFire - Remove Single Item

Here is the relevant code in my view:
p(ng-repeat="t in todos")
input(
type="checkbox",
ng-model="t.done",
ng-click="clearItem($event)"
)
{{t.text}} done? {{t.done}}
When the checkbox is clicked, I want the appropriate object in the todos array to be removed from the database.
My clearItem function is as follows:
$scope.clearItem = function(event) {
todoRef.remove($scope.t);
}
However, this removes all the entries in my database. I want it to remove only the specific object in question. Is there anyway for me to do this?
Ok, figured it out.
When looping using ng-repeat, use (id, t) in todos. This allows you to send id as the parameter to the ng-click function, and $scope.todos.$remove(id) works just fine.
To provide a more complete example for anyone else that lands here, according to Firebase's documentation for AngularFire this would be the preferred way, and I believe the easiest way to remove an object:
// Create an app. Synch a Firebase array inside a controller
var myApp = angular.module("myApp", ["firebase"]);
// inject $firebaseArray
myApp.controller("TodoCtrl", ["$scope", "$firebaseArray", function($scope, $firebaseArray) {
// bind $scope.todos to Firebase database
$scope.todos = $firebaseArray(myFirebaseRef.child("todo"));
// create a destroy function
$scope.removeTodo = function(todo) {
$scope.todos.$remove(todo);
};
}]);
In your view, you could do something like below. Note that you could bind the removeTodo function to a checkbox as the question specifies, or a regular old <a href> element:
// In your view
<div ng-controller="TodoCtrl">
<ul>
<li ng-repeat="todo in todos">
{{ todo.text }} : <a href ng-click="removeTodo(todo)">X</a>
</li>
</ul>
</div>
Hope that helps!
A better solution would be to have $scope.clearItem() take the object t as an argument, instead of $event.
HTML - <p ng-repeat="t in todos"><input... ng-click="clearItem(t)">
JS - $scope.clearItem = function(obj) {todoRef.$remove(obj)};
The only way I'm able to remove the item is using a loop on the array we get from firebase.
var ref= new Firebase('https://Yourapp.firebaseio.com/YourObjectName');
var arr_ref=$firebaseArray(ref);
for(var i=0;i<arr_ref.length;i++){
if(key==arr_ref[i].$id){
console.log(arr_ref[i]);
arr_ref.$remove(i);
}
}
The easiest way to remove the object would be
scope.clearItem = function(event) {
todoRef.$loaded().then(function(){
todoRef.$remove($scope.t)
});
The asynchronous nature of the beast has gotten me a few times.

AngularJS - Using a Service as a Model, ng-repeat not updating

I'm creating an ajax search page which will consist of a search input box, series of filter drop-downs and then a UL where the results are displayed.
As the filters part of the search will be in a separate place on the page, I thought it would be a good idea to create a Service which deals with coordinating the inputs and the ajax requests to a search server-side. This can then be called by a couple of separate Controllers (one for searchbox and results, and one for filters).
The main thing I'm struggling with is getting results to refresh when the ajax is called. If I put the ajax directly in the SearchCtrl Controller, it works fine, but when I move the ajax out to a Service it stops updating the results when the find method on the Service is called.
I'm sure it's something simple I've missed, but I can't seem to see it.
Markup:
<div ng-app="jobs">
<div data-ng-controller="SearchCtrl">
<div class="search">
<h2>Search</h2>
<div class="box"><input type="text" id="search" maxlength="75" data-ng-model="search_term" data-ng-change="doSearch()" placeholder="Type to start your search..." /></div>
</div>
<div class="search-summary">
<p><span class="field">You searched for:</span> {{ search_term }}</p>
</div>
<div class="results">
<ul>
<li data-ng-repeat="item in searchService.results">
<h3>{{ item.title }}</h3>
</li>
</ul>
</div>
</div>
</div>
AngularJS:
var app = angular.module('jobs', []);
app.factory('searchService', function($http) {
var results = [];
function find(term) {
$http.get('/json/search').success(function(data) {
results = data.results;
});
}
//public API
return {
results: results,
find: find
};
});
app.controller("SearchCtrl", ['$scope', '$http', 'searchService', function($scope, $http, searchService) {
$scope.search_term = '';
$scope.searchService = searchService;
$scope.doSearch = function(){
$scope.searchService.find($scope.search_term);
};
$scope.searchService.find();
}]);
Here is a rough JSFiddle, I've commented out the ajax and I'm just updating the results variable manually as an example. For brevity I've not included the filter drop-downs.
http://jsfiddle.net/XTQSu/1/
I'm very new to AngularJS, so if I'm going about it in totally the wrong way, please tell me so :)
In your HTML, you need to reference a property defined on your controller's $scope. One way to do that is to bind $scope.searchService.results to searchService.results once in your controller:
$scope.searchService.results = searchService.results;
Now this line will work:
<li data-ng-repeat="item in searchService.results">
In your service, use angular.copy() rather than assigning a new array reference to results, otherwise your controller's $scope will lose its data-binding:
var new_results = [{ 'title': 'title 3' },
{ 'title': 'title 4' }];
angular.copy(new_results, results);
Fiddle. In the fiddle, I commented out the initial call to find(), so you can see an update happen when you type something into the search box.
The problem is that you're never updating your results within your scope. There are many approaches to do this, but based on your current code, you could first modify your find function to return the results:
function find(term) {
$http.get('/json/search').success(function(data) {
var results = data.results;
});
//also notice that you're not using the variable 'term'
//to perform a query in your webservice
return results;
}
You're using a module pattern in your 'public API' so your searchService returns the find function and an array of results, but you'd want to make the function find to be the responsible for actually returning the results.
Setting that aside, whenever you call doSearch() in your scope, you'd want to update the current results for those returned by your searchService
$scope.doSearch = function(){
$scope.searchService.results = searchService.find($scope.search_term);
};
I updated your jsfiddle with my ideas, is not functional but i added some commments and logs to help you debug this issue. http://jsfiddle.net/XTQSu/3/

Resources