How to implement Infinite Scrolling for AngularJS & MVC - angularjs

I created one angular JS application using MVC 4
where i created one view which renders templates in that we have one template which contains large amount of data as one lack records for that i am looking to implement Infinite Scrolling
1.index.cshtml
<div id="sidebar-left" class="span2">
<div class="nav-collapse sidebar-nav">
<ul class="nav nav-tabs nav-stacked main-menu">
<li class="navbar-brand">Talks</li>
<li class="navbar-brand">SRDNames</li>
<li class="navbar-brand">Speakers</li>
<li class="navbar-brand">Add Talk</li>
</ul>
</div>
</div>
SRDNames.cshtml
<div class="box-content">
<table class="table table-striped table-bordered bootstrap-datatable datatable">
<tr>
<th>
SRD_NAME
</th>
<th>
CREATED_BY_USER_ID
</th>
</tr>
<tr ng-repeat="srdname in srdnames">
<td>
{{srdname.sRD_NAME}}
</td>
<td>
{{srdname.cREATED_BY_USER_ID}}
</td>
</tr>
</table>
3.eventModule.js
var eventModule = angular.module("eventModule", []).config(function ($routeProvider, $locationProvider) {
//Path - it should be same as href link
$routeProvider.when('/Events/Talks', { templateUrl: '/Templates/Talk.html', controller: 'eventController' });
$routeProvider.when('/Events/Speakers', { templateUrl: '/Templates/Speaker.html', controller: 'speakerController' });
$routeProvider.when('/Events/AddTalk', { templateUrl: '/Templates/AddTalk.html', controller: 'talkController' });
$routeProvider.when('/Events/SRDNames', { templateUrl: '/Templates/SRDNames.html', controller: 'srdnamescontroller' });
$locationProvider.html5Mode(true);
});
srdnamescontroller.js
eventModule.controller("srdnamescontroller", function ($scope, EventsService) {
EventsService.getSRDName().then(function (srdnames) { $scope.srdnames = srdnames }, function ()
{ alert('error while fetching talks from server') })
});
5.EventsService.js
eventModule.factory("EventsService", function ($http, $q) {
return {
getSRDName: function () {
// Get the deferred object
var deferred = $q.defer();
// Initiates the AJAX call
$http({ method: 'GET', url: '/events/GetSRDName' }).success(deferred.resolve).error(deferred.reject);
// Returns the promise - Contains result once request completes
return deferred.promise;
},
});
looking to implement like http://jsfiddle.net/vojtajina/U7Bz9/ in above application.. please help

Demo
There are many possible solutions. Here is one that may work for you.
Implement a scroll module that defines the following:
An infiniteScroll directive
A data service to get the scrollable data
You can use the scroll module from within your app:
HTML:
<div ng-app="app" ng-controller="ctrl">
<div infinite-scroll="items">
</div>
</div>
JS:
var app = angular.module('app', ['scroll']);
app.controller('ctrl', function($scope, dataService) {
$scope.items = [];
dataService.loadMore($scope.items, function(lastItem) {
var items = [];
var id = lastItem ? lastItem.id : 0;
for (var i = 0; i < 5; i++) {
items.push({id: id + i});
}
return items;
});
});
The dataService exposes a loadMore method that accepts an array, and a callback function to load more data. The above example loads more data by looping through 5 items, and adding to the array. But you can customize this function callback to retrieve data from another service:
var app = angular.module('app', ['scroll']);
app.controller('ctrl', function($scope, $http, dataService) {
$scope.items = [];
dataService.loadMore($scope.items, function(lastItem, done) {
var lastItemId = lastItem ? lastItem.id : '';
$http({ method: 'GET',url:'api/items/' + lastItemId})
.success(function(items) {
done(items);
});
});
});

Related

Passing values from controller to controller in AngularJs using Factory

I trying to pass a value from controller1 to controller2 using factory on ng-click, now i have added routing
var app = angular.module("myApp", ['ui.router']);
app.config(function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/home');
$stateProvider
.state('ShowData', {
url: '/ShowData',
templateUrl: '../Pages/Show.html'
})
.state('EditData', {
url: '/EditData',
controller:'Editctrl',
templateUrl: '../Pages/Edit.html'
})
});
app.controller('Controller1', function ($scope, $http, Phyfactory) {
//Here I am calling a factory
$scope.open = function (name) {
var message = name;
console.log('Hcpname', message);
Phyfactory.set(message);
$location.url('/EditData');
// this is my second controller
app.controller('Editctrl', function ($scope, Phyfactory) {
alert('cntrl2');
$scope.fks = Phyfactory.get();
});
I want to bind this value to textbox
<div ng-controller="Controller2">
Name: <input type="text" ng-model="fks" />
</div>
//this is my factory
app.factory("Phyfactory", function () {
var phyname = {};
function set(data) {
phyname = data;
alert('Inside set :' + phyname);
}
function get() {
alert('Inside get :' + Object.values(phyname));
return phyname;
}
return {
set: set,get:get
}
})
Adding HTML part for controller1 as requested, i am calling ng-click inside td
<div ng-app="myApp" ng-controller="controller1"
<table class="wtable">
<tr>
<th class="wth">
A
</th>
<th class="wth">
B
</th>
</tr>
<tr ng-repeat="tab in Phyperform | filter:search.view_nm|filter:search.time_period|filter:search.team_nm">
<td class="wtd" ><a ng-click="open(tab.A)"> {{tab.A}} </a> </td>
<td class="wtd"> {{tab.B}} </td>
</tr>
</table>
Value is not passing to controller2 and not redirecting as well.
Any idea?
window.location.href
will redirect to out of the app, you must use routing with $location.
of course a better way to pass data between controllers is using event!
using event like below :
this is event receiver in controller 2:
$scope.$on('myCustomEvent', function (event, data) {
console.log(data); // 'Data to send'
});
and this is the sender event in controller 1:
$scope.$emit('myCustomEvent', 'Data to send');
Credit goes to this post "Sharing Data between pages in AngularJS returning empty"
I able to do using sessionStorage.

Updating current list from one controller to another in angularjs?

Im having issues updating a list. I have tried both rootscope and using factory but it just doensn't update the view. Rather it remains the same. The only time the update works is if the list is empty to begin with otherwise the original load is always there. Appreciate any suggestions.
Here is my attempt using rootscope:
rootscope alternative
app.config(['$routeProvider', function($routeProvider){
$routeProvider
.when('/',{
replace:true,
templateUrl: 'views/questions.html',
controller: 'SiteController as vm'
})
.when('/categories',{
templateUrl: 'views/categories.html',
controller: 'CategoriesCtrl as cm'
})
.when('/categories/:name*',{
templateUrl: 'views/questions.html',
controller: 'SiteController as vm'
})
.otherwise({
redirectTo: '/'
})
}]);
index.html
<div class="col-xs-12 col-sm-8 col-md-8" ng-view>
All views load here
</div>
questions.html
<table class="table table-questions">
<thead>
</thead>
<tbody>
<tr dir-paginate-start="q in vm.allquestions>
<td>
<a class="questionlinks" ng-click="vm.viewquestion(q.idquestion)> {{q.question}} </a><h4></h4>{{q.date }}
</td>
<td class="text-center"><span class="box box-blue"> {{q.clicks}} </span></td>
</tr >
</tbody>
</table>
categories.html
<div class="wrapper content content-categories content-tags" id="categories_content">
<h2>Categories</h2>
<div class="col-md-12">
<ul class="list-tags" ng-repeat="c in cm.categories">
<li><a ng-href="#/categories{{c.categoryurl}}" ng-click="cm.getCategoryQuestions(c.idcategory)">{{c.categoryname}}</a></li>
</ul>
</div>
<div class="col-md-12">
<nav>
</nav>
</div>
</div >
Now the controllers
SiteController
(function () {
'use strict';
angular
.module('app')
.controller('SiteController', SiteController);
SiteController.$inject = ['$http','$route','$routeParams','$rootScope'];
function SiteController($http,$route,$routeParams,$rootScope) {
var vm = this;
vm.allquestions=[];
vm.thequestions=thequestions;
init();
function init(){
thequestions();
}
function thequestions() {
var url;
$rootScope.$on('updateQs',function(event, obj){
url=obj;
$http.get(url).then(function (response) {
vm.allquestions=response.data;
});
});
$http.get("/getlatestquestions").then(function (response) {
vm.allquestions=response.data;
});
}
}
})();
Categories Controller
(function () {
'use strict';
angular
.module('app')
.controller('CategoriesCtrl', CategoriesCtrl);
CategoriesCtrl.$inject = ['$http','$rootScope'];
function CategoriesCtrl($http,$rootScope) {
var cm = this;
cm.categories=[];
cm.categoryquestions=[];
//CATEGORIES
cm.getCategories=getCategories;
cm.getCategoryQuestions= getCategoryQuestions;
init();
function init(){
getCategories();
}
//CATEGORIES RELATED
function getCategories() {
var url="/getcategories";
var categoryPromise=$http.get(url);
categoryPromise.then(function (response) {
cm.categories=response.data;
})
}
function getCategoryQuestions(idcategory) {
var url="/getcategoryquestions"+idcategory;
$rootScope.$emit('updateQs',url);
}
}
})();
Factory alternative
Added this in the app.module file under app.config
app.factory("newquestions", function () {
var questions = {};
return {
setQs: function (value) {
questions = value;
},
getQs: function () {
return questions;
}
};
});
This in SiteController
(function () {
'use strict';
angular
.module('app')
.controller('SiteController', SiteController);
SiteController.$inject = ['$http','$route','$routeParams','newquestions'];
function SiteController($http,$route,$routeParams,newquestions) {
var vm = this;
vm.allquestions=[];
vm.thequestions=thequestions;
init();
function init(){
initial();
thequestions();
}
function initial(){
newquestions.setQs("/getlatestquestions");
}
function thequestions() {
var url=newquestions.getQs();
$http.get(url).then(function (response) {
vm.allquestions=response.data;
});
}
}
})();
This in CategoriesController
(function () {
'use strict';
angular
.module('app')
.controller('CategoriesCtrl', CategoriesCtrl);
CategoriesCtrl.$inject = ['$http','newquestions'];
function CategoriesCtrl($http,newquestions) {
var cm = this;
cm.categories=[];
cm.categoryquestions=[];
//CATEGORIES
cm.getCategories=getCategories;
cm.getCategoryQuestions= getCategoryQuestions;
init();
function init(){
getCategories();
}
//CATEGORIES RELATED
function getCategories() {
var url="/getcategories";
var categoryPromise=$http.get(url);
categoryPromise.then(function (response) {
cm.categories=response.data;
})
}
function getCategoryQuestions(idcategory) {
var url="/getcategoryquestions"+idcategory;
newquestions.setQs(url);
}
}
})();
It wouldn't work. There is no way to know either of your controllers to know that list has changed.
Solution
Use event broadcasts.
Broadcast or emit an event from two controllers. And use it as a trigger point.

angularjs object list not binding to ng-repeat

I am using angular 1.5.5 with ui router 0.2.14. I have the view of employee list to be displayed. EmployeeList template is as follows:
<table class="employeeListContainer">
<tr ng-repeat="employee in employees">
<td>
<a ng-bind="employee.EmployeeId" class="employeeId"></a>
<!--ui-sref="employeeDetails{ employeeId: employee.EmployeeId }"-->
</td>
<td ng-bind="employee.FirstName"></td>
<td ng-bind="employee.LastName"></td>
</tr>
<tr>
<td colspan="3" class="paging">
<button ng-disabled="!IsPrevButtonEnabled" ng-click="prevPage()" class="prev-next"><</button>
<span ng-bind="PageNumber"></span>
<button ng-disabled="!IsNextButtonEnabled" ng-click="nextPage()" class="prev-next">></button>
</td>
</tr>
<tr>
<td colspan="3" class="paging">
<span ng-bind="ErrorMessage" ng-show="IsError"></span>
</td>
</tr>
</table>
I have configured the app as follows:
var app = angular.module('app', ['ui.router']);
app.config(function ($urlRouterProvider, $stateProvider, $httpProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider.state('employeeList', {
url: '/List',
templateUrl: '../../Templates/EmployeeList.html',
controller: 'EmployeeListController',
resolve: {
employeeListRs: function (dataService) {
var employeeListRq = getEmployeeListRqInit();
return dataService.callApi('GetEmployees', 'post', [employeeListRq])
.then(function (data) { return data.data; });
},
employeeListRq: function(){
return getEmployeeListRqInit();
},
greeting: function ($q, $timeout) {
var deferred = $q.defer();
$timeout(function () {
deferred.resolve('Hello!');
}, 1000);
return deferred.promise;
}
}
});
$stateProvider.state('default', {
url: '/',
//templateUrl: '../../Templates/EmployeeList.html',
controller: 'defaultController'
});
$httpProvider.defaults.headers.common = {};
$httpProvider.defaults.headers.post = {};
$httpProvider.defaults.headers.put = {};
$httpProvider.defaults.headers.patch = {};
var getEmployeeListRqInit = function () {
return {
PageNumber: 1,
PageSize: 10,
SessionId: "123"
};
}
});
dataService is a service that is wrapper to the original $http.post call. Controller code is as follows:
app.controller('EmployeeListController', function ($scope, employeeListRq, employeeListRs, greeting) {
$scope.PageNumber = employeeListRq.PageNumber;
$scope.PageSize = employeeListRq.PageSize;
$scope.IsError = !employeeListRs.IsSuccess;
$scope.TotalCount = (employeeListRs.EmployeeList == null) ? 0 : employeeListRs.EmployeeList.TotalCount;
$scope.employees = (employeeListRs.EmployeeList == null) ? null : employeeListRs.EmployeeList.Employees;
if ($scope.employees = null) return 1;
var remainder = $scope.TotalCount % $scope.PageSize;
var pageNumber = Math.floor($scope.TotalCount / $scope.PageSize);
var lastPageNumber = remainder > 0 ? pageNumber + 1 : pageNumber;
$scope.IsNextButtonEnabled = $scope.PageNumber != lastPageNumber;
$scope.IsPrevButtonEnabled = $scope.PageNumber != 1;
$scope.IsLoading = false;
$scope.ErrorMessage = employeeListRs.IsSuccess ? '' : employeeListRs.ErrorMessage;
});
I see while debugging in chrome that $scope.employees is set to an array containing 10 objects all with proper fields and values. Also the IsPrevButtonEnabled and IsNextButtonEnabled are set perfectly. The binding is reflected on UI too, perfectly.
But I don't see the table containing employees list. Any suggestions on what I am missing?
Note: I don't get any error on console.
A few things you can try:
(1) Not saying yours is incorrect, but the preferred way to bind the data would be to use expressions. So, instead of this:
<td ng-bind="employee.FirstName"></td>
try this:
<td>{{employee.FirstName}}</td>
(2) This line looks suspicious in your controller:
if ($scope.employees = null) return 1;
It looks like you are assigning a null value to $scope.employees instead of checking for null. I/my teams try to use angular.isDefined($scope.employees) when we want to check for existence.
What are you trying to accomplish with that line?
(3) This looks a little different than how I use services and how I see others use them:
resolve: {
employeeListRs: function (dataService)
It looks to me that employeeListRs returns a promise.
What I typically do is call the service (my angular service which in turn calls the $http service) from inside the controller and then handle the response (both expected and error responses). From there I push the data into the controller's model. I haven't yet mixed service calls into my state machines - I let the controllers make the service calls.
(4) What is inside this css class - employeeListContainer? Could there be something there hiding your table? You might want to share your html and css as well.

AngularJS Variables across Views (same controller)

I've got an AngularJS app that has (for now) just one controller but multiple views. All of this data is pulled via $http.
In one view, it's got an ng-repeat for 'leagues'. It's got a button that has an ng-click to take the amount of teams for that league and the amount of players per team and pass them to a function and set them as variables. That function also redirects the view to another page with $location.
In that page, it's got binds to look at those variables. However, nothing shows. It can LOG the information but it won't show it when the view changes.
Here's my git repo for it.
leagues.html, line 27 for the ng-click that calls the function in list item 3, below, and to send to teams.html.
teams.html, to show the variables (for testing, I was just trying to display them before creating another ng-repeat)
public/javascripts/app.js, line 63 for the function to render the variables.
Most of the answers for this tend to say "use different views" or "use ui-router". Why doesn't this work?
Please see my code snippets below.
leagues.html
<div class="container col-md-12">
<h1>Manage Leagues</h1>
<div class="table-responsive">
<table class="table">
<tr>
<th>League Name</th>
<th>Location</th>
<th>Start Date</th>
<th>Duration</th>
<th>Team Count</th>
<th>Courts</th>
<th>Format</th>
<th>Manage League</th>
<th>Add Players</th>
<th>Archive</th>
</tr>
<tr ng-repeat="league in leagues">
<td>{{league.league_name}}</td>
<td>{{league.park_location}}</td>
<td>{{league.start_date | date:'dd-MM'}}</td>
<td>{{league.league_duration}}</td>
<td>{{league.team_count}}</td>
<td>{{league.court_ct}}</td>
<td>{{league.player_count}}</td>
<td><a class="btn btn-success">Manage</a></td>
<!-- This currently only logs that player and team count-->
<td><button class="btn btn-success" ng-click="createTeam(league.id,league.team_count,league.format)">Add</button></td>
<!-- //-->
<td><button class="btn btn-danger" ng-click="archiveLeague(league.id)">Archive</button></td>
</tr>
</table>
</div>
</div>
teams.html
<div class="container">
<h1>Create Teams</h1>
<h3>{{current-id}}</h3>
<h3>{{current-teams}}</h3>
<h3>{{current-format}}</h3>
<h3>Done</h3>
</div>
public/javascripts/app.js
/**
* Created by nhyland on 7/16/15.
*/
var myApp = angular.module('myApp', ['ngRoute']);
myApp.config(function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: "/pages/main.html",
controller: 'mainController',
map: 'main'
})
.when('/leagues', {
templateUrl: "/pages/leagues.html",
controller: 'mainController',
map: 'leagues'
})
.when('/create', {
templateUrl: "/pages/create.html",
controller: 'mainController',
map: 'create'
})
.when('/create/team', {
templateUrl: "/pages/teams.html",
controller: 'mainController',
map: 'teams'
})
.otherwise({
template: "<h1>Page does not exist.</h1>"
});
});
myApp.controller('mainController', function($scope, $http, $location) {
$scope.test = "Angular is working";
$scope.createLeague = function() {
$scope.league.archived = 0;
$http.post('/app/create/league', $scope.league)
.success(function(data) {
console.log(data);
$scope.leagueInfo = data;
$scope.leagues = {};
$location.path("/leagues");
})
.error(function(error) {
console.log('Error: ' + error);
});
};
function getLeagues() {
$http.get('/app/leagues/director/' + director)
.success(function(data) {
console.log(data);
$scope.leagues = data;
})
.error(function(error) {
console.log(error);
})
}
getLeagues();
$scope.createTeam = function(id, teams, format) {
console.log('League Details: ' + id);
console.log('League Details: ' + teams);
console.log('League Details: ' + format);
$scope.currentId = id;
$scope.currentTeams = teams;
$scope.currentFormat = format;
$location.path('/create/team');
$scope.getNum = function(num) {
return new Array(num);
};
};
$scope.archiveLeague = function(id) {
$http.put('/app/leagues/archive/' + id + '/' + director)
.success(function(data) {
console.log(data);
$scope.leagues = data;
})
.error(function(error) {
console.log(error);
})
};
});
It does not work because every time the route change, a new controller instance is created. This means that your scope is reinitialized and you therefore lose the value you wanted to save. To see this, simply inspect element in your browser and put a break point at the begining of your controller. You will see that a new instance is created when your view changes. (your $scope will change)
It is recomended to have only one controller per view and use services or factories when you want to share data across controllers.

AngularJS with MongoDB, data is pulled from database, but cannot display with ng-repeat

I am trying to get data from the DB and display it using ng-repeat. The getAll function from the factory does the job properly, I get an object with all the data, but it is not displayed properly. In the table I only get the first index, with nothing after it.
If i try with for(i = 0 ; i < DataService.persons.length ; i++), it works fine, but I cannot use it with ng-repeat.
var testReactie = angular.module('testReactie', ['ngRoute']);
testReactie.config(function($routeProvider) {
$routeProvider
.when('/', {
templateUrl : 'instructiuni.ejs'
})
.when('/form', {
templateUrl : 'form.ejs',
controller : 'formContr'
})
.when('/test', {
templateUrl : 'joc.ejs',
controller : 'gameContr'
})
.when('/stat', {
templateUrl : 'scoruri.ejs',
controller : 'statContr',
resolve: {
postPromise:['DataService', function(DataService){
return DataService.getAll();
}]
}
});
});
testReactie.factory('DataService', ['$http', function($http) {
var o = {
persons:[],
person:{}
};
o.getAll = function(){
return $http.get('/db').success(function(data){
o.persons = data;
});
};
o.create = function() {
return $http.post('/db', o.person).success(function(data){
o.persons.push(data);
});
};
return o;
}]);
testReactie.controller('mainContr',function($scope) {
});
testReactie.controller('statContr',function($scope, DataService) {
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<h2>Scoruri</h2>
<table class="table">
<thead>
<tr>
<th>Nr.</th>
<th>Sex</th>
<th>Varsta</th>
<th>Timp Mediu</th>
</tr>
</thead>
<tbody>
<div ng-repeat = "pers in DataService.persons">
<tr>
<td>{{$index + 1}}</td>
<td>{{pers.sex}}</td>
<td>{{pers.varsta}}</td>
<td>{{pers.timp}}</td>
</tr>
</div>
</tbody>
</table>
</div>
You cannot run a factory as a controller
In your controller do something like
testReactie.controller('mainContr', ['DataService', '$scope', function(DataService, $scope) {
DataService.getAll().then(function(successData){ // a promise helps you do something when it's resolved
$scope.awesomeData = successData;
}
});
Change your factory's get all to be something like
o.getAll = function(){
var promise = $q.defer(); // the $q helps create a promise
return $http.get('/db').success(function(data){
promise.resolve(data); // promise returns data when resolved
});
return promise; // returns a promise
};
your template should be
<div ng-repeat = "pers in awesomeData">
This is because when you have it in your template, it will automatically call $scope.awesomeData. So when you had DataService then it was calling $scope.DataService which was undefined.
I hope this helps.
I fixed the problem. It was from the HTML. I added the ng-repeat directive in a div and it broke the table. After deleting the div and adding the directive in the tag, it worked fine.

Resources