Currently in Angular I am making an http request to a JSON news feed. I'm initiating the http request on load with data-ng-init="init()". However I would like the show just one article and have an infinite scroll. In other words, I would like the other articles to load, once a user gets to the bottom of each article.
This is my current index.html
<section ng-app="sports" ng-controller="main" data-ng-init="init()">
<div ng-repeat="article in articles | limitTo:2">
<div class="col-lg-8 col-lg-offset-2 col-md-8 col-md-offset-2 col-sm-8 col-sm-offset-2">
<!-- <h3>{{ article.created }}</h3> -->
<h1>{{ article.title }}</h1>
<img class="images afkl-lazy-image" src="{{ article.thumbnail }}">
<p ng-bind-html=" article.body | html "></p>
</div>
</div>
</section>
And here is my angularApp.js:
app.controller('main', function($scope, $http){
$scope.init = function(){
$http.get("/data")
.success(function(response) {
$scope.articles = [];
$.each(response.node,function(index,item){
$scope.articles.push(item);
})
$scope.articles.reverse();
});
}}
);
I will be around to answer any questions. Thank you in advance!!
You just need to add a scroll listener to the page, catch the event and load more data one "page" at a time:
$scope.currentPage = 0;
$scope.loadPage = function(pageNum){
$http.get("/data?page=" + pageNum)
.success(function(response) {
$scope.currentPage = pageNum;
$.each(response.node,function(index,item){
$scope.articles.push(item);
})
});
}}
};
window.onscroll = function(ev) {
if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) {
$scope.loadPage($scope.currentPage + 1);
}
};
You should really inject $window service and use it:
...controller('mycontroller', function($scope, $window) {
angular.element($window).bind("scroll", function() {
///check to see if you're at the bottom and call method to load data as above
});
});
Related
I am trying to make a UI using list of product in a json(products.json) file on local and their availability in number from wp rest api call back in html(ionic) I have this:
Controller:
.controller('ShopCtrl', function($scope, $ionicActionSheet, BackendService, CartService, $http, $sce ) {
$scope.siteCategories = [];
$scope.cart = CartService.loadCart();
$scope.doRefresh = function(){
BackendService.getProducts()
.success(function(newItems) {
$scope.products = newItems;
console.log($scope.products);
})
.finally(function() {
// Stop the ion-refresher from spinning (not needed in this view)
$scope.$broadcast('scroll.refreshComplete');
});
};
$http.get("http://example.com/wp-json/wp/v2/categories/").then(
function(returnedData){
$scope.siteCategories = returnedData.data;
console.log($scope.siteCategories);
}, function(err){
console.log(err);
});
Template view:
<div ng-repeat = "product in products">
<div class="item item-image" style="position:relative;">
<img ng-src="{{product.image}}">
<div ng-repeat = "siteCategory in siteCategories">-->
<button class="button button-positive product-price" ng-click="addProduct(product)">
<p class="white-color product-price-price">post <b>{{siteCategory[$index].count}}</b></p>
</button>
</div>
</div>
<div class="item ui-gradient-deepblue">
<h2 class="title white-color sans-pro-light">{{product.title}} </h2>
</div>
<div class="item item-body">
{{product.description}}
</div>
</div>
so how can I achieve that? I tried to use nested ng-repeat but it didn't work out.
Intially when i use / i can see home.html getting sucessufully to index.html then i click <a ng-href="#/club> the club page is loaded successfully, but then i press back button then only header and footer of home.html is seen and in between complete blank page
Below are following files:
appRoutes.js --> for routing on angular side
clubCtrl.js --> club controller
clubService.js --> club service to fill data from node
Routes.js --> partial sample of retriving data from database and sending response
club.html --> partial club view file
home.html --> partial home page
index.html --> file on which club.html will get dynamically displayed using ng-view.
app.js -> injecting all modules
appRoutes.js
angular.module('appRoutes', []).config(['$routeProvider', function($routeProvider) {
$routeProvider
// home page
.when('/', {
templateUrl: 'views/home.html',
controller: 'MainController'
})
// nerds page that will use the NerdController
.when('/club', {
templateUrl: 'views/club.html',
controller: 'ClubController'
});
}]);
ClubCtrl.js
angular.module('ClubCtrl', []).controller('ClubController', [ '$http','Club', function($http, Club) {
var club = this;
club.data = {};
Club.getClubData().then(function(response){
club.data = response.data;
});
}]);
ClubService.js
angular.module('ClubService', []).factory('Club', ['$http', function($http) {
return {
getClubData : function() {
return $http.get('/api/club');
}
};
}]);
Routes.js
module.exports = function(app) {
app.get('/', function(req, res) {
console.log("routes send get(*)");
res.sendFile(path.resolve('public/index.html')); // load our public/index.html file
});
app.get('/api/club', function(req, res){
console.log("routes send get /club");
con.query("select * from club_data", function(err, rows,field) {
if (!err)
{
console.log('The solution is: ', rows);
res.json(rows);
}
else
console.log('Error while performing Query. ', err);
});
});
};
Club.html
</div>
<div class="row " >
<div class="col-md-3 col-sm-6 image-feature" ng-repeat='dat in main.data'>
<div class="thumbnail">
<img ng-src="images/club/{{dat.imagename}}"alt="">
<div class="caption">
<h3>{{ dat.name }}</h3>
<p>{{dat.desccription}}</p>
<p>{{dat.date}}</p>
<p>
I'm Going!
</p>
</div>
</div>
</div>
home.html
<h1>Party</h1>
<div class="divider"></div>
<p>"Anytime I'm at a club or a party, I'm dancing from beginning to end."<br>--Agnes Bruckner</p>
</div>
<div class="row">
<div class="col-md-3 col-sm-3 col-xs-6">
<div class="about-item scrollpoint sp-effect2">
index.html
<body ng-app="staygala" ng-controller="MainController">
<!-- ANGULAR DYNAMIC CONTENT -->
<div ng-view></div>
</body>
app.js
angular.module('staygala', ['ngRoute', 'appRoutes', 'MainCtrl', 'ClubCtrl', 'ClubService']);
On browser console:
Uncaught TypeError: Cannot read property 'restart' of undefined i'm seeing this error while i press back. Also it looks there is no call to Get / when i press back button but when page starts there is call to same
I am just trying to get the ng-show tag working and to test it, I have a hard coded example and even this doesn't work (it is visible when the page loads). Code below.
#{
ViewBag.Title = "Secure Environment Flex";
}
<div class="row">
<div class="col-md-12">
<h3>Secure Environment</h3>
</div>
</div>
<div ng-controller="SEFlexHomeController" ng-show="false">
<div >
<div >
<ul>
<li>Jobs</li>
<li>Models</li>
<li>Administration</li>
</ul>
<div id="tabs-Jobs" >
<h1>Welcome to this jobs tab</h1>
</div>
<div id="tabs-Models">
<h1>Welcome to this models tab</h1>
</div>
<div id="tabs-Administration" >
<h1>Welcome to this administration tab</h1>
</div>
</div>
</div>
</div>
This is driving me mad, why is it still visible? Could something else in CSS be overriding it and if so how can I tell?
EDIT: Ok I got it working with a basic variable in scope like suggested. Now I'm trying to link it up to the actual action. My code retrieves a list of permissions in the background and once those are retrieved, I want to either display the page or an error depending on if the user is permissioned. Whats bizarre now is that I have two sections, page and error, one with ng-show matching the determination function and one with the negated function. But they are both showing? If I change them both to be just the function "isPermissioned" then the top one shows and the bottom doesn't, so it looks like they are getting different values from the same function. Could this be because one is executing before the other and when the background method updates the permissions, it isn't triggering the data binding?
New HTML is
<div ng-controller="SEFlexHomeController" ng-show="isPermissioned">
<div class="row" id="TabsSet1">
<div class="col-md-12">
<ul>
<li ng-show="AuthService.canRunFlexJobs || AuthService.canRunHighPriorityFlexJobs">Jobs</li>
<li ng-show="AuthService.canViewFlexModels">Models</li>
<li ng-show="AuthService.canAdministerFlex">Administration</li>
</ul>
<div id="tabs-Jobs" ng-show="AuthService.canRunFlexJobs || AuthService.canRunHighPriorityFlexJobs">
<h1>Welcome to this jobs tab</h1>
</div>
<div id="tabs-Models" ng-show="AuthService.canViewFlexModels">
<h1>Welcome to this models tab</h1>
</div>
<div id="tabs-Administration" ng-show="AuthService.canAdministerFlex">
<h1>Welcome to this administration tab</h1>
</div>
</div>
</div>
</div>
<div ng-show="!isPermissioned">
<h3>You have no permissions to view Secure Environment pages</h3>
</div>
JavaScript
app.controller("SEFlexHomeController", ["$scope", "$http", "$modal", "$log", "$element", "$rootScope", "AlertsService", "AuthService", "SEApplicationService", function ($scope, $http, $modal, $log, $element, $rootScope, AlertsService, AuthService, SEApplicationService) {
$rootScope.closeAlert = AlertsService.closeAlert;
$scope.isDataLoading = false;
$scope.AuthService = AuthService;
$scope.show = false;
$scope.isPermissioned = function() {
return AuthService.canAdministerFlex || AuthService.canViewFlexModels || AuthService.canRunFlexJobs || AuthService.canRunHighPriorityFlexJobs;
}
}
]);
Auth service
function AuthService($log, $http) {
var authService = {
canRunFlexJobs: false,
canRunHighPriorityFlexJobs: false,
canViewFlexModels: false,
canApproveFlexModels: false,
canAdministerFlex: false
};
authService.getUserClaims = function () {
$http.post("/Admin/Auth/GetUserClaims")
.success(function (response, status, headers, config) {
if (response) {
angular.forEach(response.data, function (item) {
if (item.Value === "SEFlexJobRunner")
authService.canRunFlexJobs = true;
if (item.Value === "SEFlexHighPriorityJobRunner")
authService.canRunHighPriorityFlexJobs = true;
if (item.Value === "SEFlexModelViewer")
authService.canViewFlexModels = true;
if (item.Value === "SEFlexModelApprover")
authService.canApproveFlexModels = true;
if (item.Value === "SEFlexAdministrator")
authService.canAdministerFlex = true;
});
}
})
.error(function (reason, status, headers, config) {
console.log(reason);
});
}
authService.getUserClaims();
return authService;
};
Well for your given code:
<div ng-controller="SEFlexHomeController" ng-show="show">
<div >
<div >
<ul>
<li>Jobs</li>
<li>Models</li>
<li>Administration</li>
</ul>
<div id="tabs-Jobs" >
<h1>Welcome to this jobs tab</h1>
</div>
<div id="tabs-Models">
<h1>Welcome to this models tab</h1>
</div>
<div id="tabs-Administration" >
<h1>Welcome to this administration tab</h1>
</div>
</div>
</div>
</div>
JS:
myAngularApp.controller('SEFlexHomeController', ['scope', function($scope) {
$scope.show = false;
// do stuff here
}]);
https://docs.angularjs.org/api/ng/directive/ngShow
<!-- when $scope.myValue is truthy (element is visible) -->
<div ng-show="myValue"></div>
<!-- when $scope.myValue is falsy (element is hidden) -->
<div ng-show="myValue" class="ng-hide"></div>
I assume you mean it's visible as the page loads and then disappears? If that's the case, you're going to want to also use ng-cloak.
Keep in mind that the css used by ng-cloak isn't available until Angular loads, so most put CSS like this in the header of their document.
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak
{
display: none !important;
}
i got an issue that I'm trying to solve but it seems I can't find a proper solution to achieve what I'm trying to do.
I'l try to explain my problem as best as I can: I need to create some tabs heading dynamically depending on the result of an AJAX call, so I don't know in advance how many tabs there will be, I'll post my HTML markup, my controller and what is the result I have in the DOM. I hope I'll be able to explain myself clear enough.
PART OF THE HTML MARKUP
<div id="tabPlacer">
</div>
PART OF ANGULARJS CONTROLLER
$http({method: 'GET', url: 'getNews.json'}).
success(function(data, status, headers, config) {
$scope.news = data;
createBase();
var contFirst=0;
var contSecond=0;
for (i=0; i< $scope.news.news[0].allNews.length; i++){
$scope.bodynews[i] = $scope.news.news[0].allNews[i].bodyNews;
if(i%2==0)
{
$scope.bodynewsR[contFirst] = $scope.news.news[0].allNews[i].bodyNews;
contFirst++;
}
else{
$scope.bodynewsL[contSecond] = $scope.news.news[0].allNews[i].bodyNews;
contSecond++;
}
}
$scope.noOfPages =Math.floor($scope.news.news[0].allNews.length / ($scope.itemsPerCol*2));
$scope.$watch('currentPage', function() {
begin = (($scope.currentPage - 1) * $scope.itemsPerCol);
end = begin + $scope.itemsPerCol;
$scope.pagedL = {
bodynewsL: $scope.bodynewsL.slice(begin, end)
}
$scope.pagedR = {
bodynewsR: $scope.bodynewsR.slice(begin, end)
}
});
}).
error(function(data, status, headers, config) {
});
function createBase() {
for (var i = 0; i < $scope.news.news[0].posizioni.length; i++) {
// $scope.tabsName[i] = $scope.news.news[0].posizioni[i][i];
$scope.baseString += "<tab heading='" + $scope.news.news[0].posizioni[i][i] + "' ng-controller='MainController'><div class='col-xs-12 col-sm-6 col-md-6' id='colonaDx"+ $scope.news.news[0].posizioni[i][i] +"'></div><div class='col-xs-12 col-sm-6 col-md-6' id='colonaDx"+ $scope.news.news[0].posizioni[i][i] +"'></div><div id='paginaz"+ $scope.news.news[0].posizioni[i][i] +"'></div></tab>";
}
$scope.baseString += "</tabset>";
$("#tabPlacer").html($scope.baseString);
}
});
HTML CREATED IN DOM
<div id="tabPlacer">
<tabset panel-tabs="true" panel-class="panel-grape" data-heading="OTHER NEWS">
<tab heading="allNews" ng-controller="MainController">
<div class="col-xs-12 col-sm-6 col-md-6" id="colonaDxallNews">
</div>
<div class="col-xs-12 col-sm-6 col-md-6" id="colonaDxallNews">
</div>
<div id="paginazallNews">
</div>
</tab>
<tab heading="SecondTab" ng-controller="MainController">
<div class="col-xs-12 col-sm-6 col-md-6" id="colonaDxSecondTab">
</div><div class="col-xs-12 col-sm-6 col-md-6" id="colonaDxSecondTab">
</div>
<div id="paginazSecondTab">
</div>
</tab>
</tabset>
</div>
So far the problem is that nothing is visualized on the page but if I manually define in the html markup the tabset structure I can see them..any ideas? Thanks very very much in advance.
As Cetia said, you don't want to "insert" html into your template in angular. Instead, your situation probably needs ng-repeat, which is one of the very basic angular directives you should learn to use.
Basically, you'll want to store the fetched data in a $scope variable, and then use that variable with ng-repeat to display things based on your data. A basic example here:
Controller:
$scope.things = [
{
name: "Thing1",
description: "I'm the first thing!"
},
{
name: "Thing2",
description: "I'm the second thing!"
}
]
HTML:
<div ng-repeat="thing in things">
<tr>
<td>{{thing.name}}:</td>
<td>{{thing.description}}</td>
</tr>
</div>
See fiddle here: http://jsfiddle.net/m8qLdhth/1/
I have a controller (called "catalogueController") that manages my search box and my search page. I have the controller initially set the page to automatically call the search function defined in "catalogueController" when the app loads to pre-load my array of items (called Inventory) to be repeated via ng-repeat in the page.
The process runs like this:
1. I submit the search form.
2. "catalogueController" will send the search term to my factory (called "Search").
3. "Search" will have a function which will make a server call to query my database for that particular search.
4. The database will send the results of the search to the "Search" factory.
5. The "Search" factory will send the results to the "catalogueController" controller.
6. "catalogueController" will update the $scope.Inventory to be equal to the new result that I was received.
My problem is that ng-repeat does not refresh itself to display my new and updated $scope.Inventory array. $scope.Inventory definitely is updated (I have made sure of this through various console logs).
I have also tried to use $scope.$apply(). It did not work for me.
Thank you in advance for your help!
Here is my code:
HTML Template
<form role="search" class="navbar-form navbar-left" ng-controller="catalogueController" ng-submit="search(search_term)">
<div class="form-group">
<input type="text" placeholder="Search" class="form-control" ng-model="search_term">
</div>
<button type="submit" class="btn btn-default">Search</button>
</form>
<main ng-view></main>
catalogue.html partial
<div id="main" class="margin-top-50 clearfix container">
<div ng-repeat="items in inventory" class="row-fluid">
<div class="col-sm-6 col-md-3">
<div class="thumbnail"><img src="image.jpg" alt="..." class="col-md-12">
<div class="caption">
<h3>{{ items.itemName }}</h3>
<p>{{ items.description }}</p>
<p>Buy <a href="#" role="button" class="btn btn-default">More Info</a></p>
</div>
</div>
</div>
</div>
"app.js" Angular App
var myApp = angular.module('qcbApp', ['ngRoute', 'ngCookies', 'appControllers']);
myApp.config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/login', {
templateUrl: 'html/partials/login.html',
controller: 'registrationController'
}).
when('/sign-up', {
templateUrl: 'html/partials/sign-up.html',
controller: 'registrationController'
}).
when('/catalogue', {
templateUrl: 'html/partials/catalogue.html',
controller: 'catalogueController'
}).
when('/', {
templateUrl: 'html/partials/qcbhome.html'
}).
otherwise({
redirectTo: '/'
});
}]);
"catalogueController" Controller
myApp.controller('catalogueController', ['$scope', 'Search', function($scope, Search) {
var time = 0;
var searchCatalogue = function(search) {
$scope.inventory = null;
console.log("Controller -- "+search);
Search.searchCatalogue(search)
.then(function(results) {
console.log(results);
$scope.inventory = results;
});
};
if(time == 0)
{
searchCatalogue('');
time++;
}
$scope.search = function(term) {
searchCatalogue(term);
}
}]);
"Search" Factory
myApp.factory('Search', ['$http', '$q', function($http, $q) {
function searchCatalogue(term) {
var deferred = $q.defer();
console.log("Factory -- "+term);
$http.post('/catalogue_data', {term: term}, {headers: {'Content-Type': 'application/json'}})
.success(function(result) {
console.log(result[0].SKU);
deferred.resolve(result);
console.log("Factory results -- "+result);
});
return deferred.promise;
}
return {
searchCatalogue: searchCatalogue
}; //return
}]);
I think the problem is the ng-repeat can not access the inventory in scope. You have to create a div which contains both the form and the ng-repeat.
The html should be:
<div ng-controller="catalogueController">
<!-- Move the controller from the form to parent div -->
<form role="search" class="navbar-form navbar-left" ng-submit="search(search_term)">
<div class="form-group">
<input type="text" placeholder="Search" class="form-control" ng-model="search_term">
</div>
<button type="submit" class="btn btn-default">Search</button>
</form>
<div id="main" class="margin-top-50 clearfix container">
<div ng-repeat="items in inventory" class="row-fluid">
<div class="col-sm-6 col-md-3">
<div class="thumbnail"><img src="image.jpg" alt="..." class="col-md-12">
<div class="caption">
<h3>{{ items.itemName }}</h3>
<p>{{ items.description }}</p>
<p>Buy <a href="#" role="button" class="btn btn-default">More Info</a></p>
</div>
</div>
</div>
</div>
</div>
I've seen the situation a few times where when you are updating a property directly on the $scope object there are interesting problems around databinding to that value (such as inventory). However if you databind to an object property of an object then the databinding works as expected. So for example use a property on $scope. I believe this is a copy by value vs copy by reference issue.
Update all your inventory references as follows
$scope.data.inventory = result;
Also don't forget to update your inventory reference in the html template:
<div ng-repeat="items in data.inventory" class="row-fluid">
Update: I made this plunk to figure it out - http://plnkr.co/edit/0ZLagR?p=preview
I think the primary problem is you have the controller specified twice. I removed it from the form and it started working.