Skip to content

Instantly share code, notes, and snippets.

@junerockwell
Last active August 29, 2015 14:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save junerockwell/1829a8789d8bb91c2e69 to your computer and use it in GitHub Desktop.
Save junerockwell/1829a8789d8bb91c2e69 to your computer and use it in GitHub Desktop.
collection-item prevents lazy images to load automatically when their already in view
.controller('RecipiesController', function($scope, RecipesFactory, $timeout, $cordovaNetwork, $ionicPlatform, $rootScope, $interval) {
$scope.recipes = [];
$scope.limit = 10;
$scope.hideIonSpinner = true;
$scope.statusMessage = "";
$scope.showStatusMessage = false;
$ionicPlatform.ready(function() {
if ($cordovaNetwork.isOnline()) {
console.log("isOnline");
pollAllRecipes(3);
} else {
console.log("! isOnline");
// pollAllRecipes(3);
$scope.hideIonSpinner = true;
$scope.showStatusMessage = true;
$scope.statusMessage = "No Internet Connection Found."
}
// listen for Online event
$rootScope.$on('$cordovaNetwork:online', function(event, networkState){
var onlineState = networkState;
$scope.hideIonSpinner = false;
$scope.showStatusMessage = false;
pollAllRecipes(3);
});
});
$scope.doRefresh = function() {
$timeout(function() {
pollAllRecipes(1);
$scope.$broadcast('scroll.refreshComplete');
}, 1000);
};
function getAllRecipes(callback) {
callback = callback || {};
RecipesFactory.GetAllRecipes()
.then(function(data) {
$scope.recipes = data;
if (typeof callback === 'function') {
if ($scope.recipes.length > 0) {
console.log($scope.recipes.length);
callback(true);
increaseLimit();
$scope.hideIonSpinner = true;
$scope.showStatusMessage = false;
} else {
callback(false);
$scope.hideIonSpinner = true;
$scope.statusMessage = "No Recipes Available. Please try again later.";
}
}
}, function(err) {
console.log("getAllRecipes: error callback");
if (typeof callback === 'function') {
callback(false);
}
});
}
function pollAllRecipes(timeoutCounter) {
$timeout(function() {
--timeoutCounter;
getAllRecipes(function(stopLooping) {
if (!stopLooping && timeoutCounter > 0) {
pollAllRecipes(timeoutCounter);
} else {
$scope.showStatusMessage = true;
$scope.statusMessage = "Service unavailable. Please try again later."
}
})
}, 1000);
}
function increaseLimit() {
var interval = $interval(function() {
$scope.limit += 10;
if ($scope.limit >= $scope.recipes.length) {
$interval.cancel(interval);
}
}, 3000);
}
})
{
"_id": {
"$oid": "54fdd165e74a79b75610ac1d"
},
"title": "Stuffed Omelet",
"imagePath": "http://fossil.cchd.org:3001/images/StuffOmelet.jpg",
"serves": 4,
"mealtimes": "Breakfast",
"directions": [
"Heat broiler. In a medium bowl, combine the mango, scallions, 1 tablespoon of the oil, lime juice, rushed red pepper, and 1/4 teaspoon salt. Set aside",
"Rub the pork with the remaining 1 teaspoon oil.",
"Broil the pork, turning occassionally, until cooked through, 12 to 15 minutes. Let rest 5 minutes before slicing.",
"Serve the pork with the salsa"
],
"ingredients": [
"1 mango, chopped",
"2 scallions, chopped",
"1 tablespoon plus 1 teaspoon olive oil",
"1 tablespoon fresh lime juice",
"1/4 teaspoon crushed red pepper",
"kosher salt",
"1 & 1/4-pound pork tenderloin",
"1 teaspoon ground coriander"
],
"__v": 0
}
/**
* Created by PAVEI on 30/09/2014.
* Updated by Ross Martin on 12/05/2014
* Updated by June Rockwell on 3/1/2015 (local only)
*/
angular.module('ionicLazyLoad', []);
angular.module('ionicLazyLoad')
.directive('lazyScroll', ['$rootScope', '$timeout',
function($rootScope, $timeout) {
return {
restrict: 'A',
link: function ($scope, $element) {
var scrollTimeoutId = 0;
$scope.invoke = function () {
// console.log('in invoke');
$rootScope.$broadcast('lazyScrollEvent');
};
$element.bind('scroll', function () {
// console.log('in scroll bind');
$timeout.cancel(scrollTimeoutId);
// wait and then invoke listeners (simulates stop event)
scrollTimeoutId = $timeout($scope.invoke, 0);
});
}
};
}])
.directive('imageLazySrc', ['$document', '$timeout',
function ($document, $timeout) {
return {
restrict: 'A',
link: function ($scope, $element, $attributes) {
var deregistration = $scope.$on('lazyScrollEvent', function () {
if (isInView()) {
$element[0].src = $attributes.imageLazySrc; // set src attribute on element (it will load image)
deregistration();
}
}
);
function isInView() {
var clientHeight = $document[0].documentElement.clientHeight;
var clientWidth = $document[0].documentElement.clientWidth;
var imageRect = $element[0].getBoundingClientRect();
return (imageRect.top >= 0 && imageRect.bottom <= clientHeight) && (imageRect.left >= 0 && imageRect.right <= clientWidth);
}
// bind listener
// listenerRemover = scrollAndResizeListener.bindListener(isInView);
// unbind event listeners if element was destroyed
// it happens when you change view, etc
$element.on('$destroy', function () {
deregistration();
});
// explicitly call scroll listener (because, some images are in viewport already and we haven't scrolled yet)
$timeout(function() {
// console.log('imageLazySrc: calling scroll listener');
if (isInView()) {
// console.log($attributes.imageLazySrc + " in view");
$element[0].src = $attributes.imageLazySrc; // set src attribute on element (it will load image)
deregistration();
}
}, 500);
}
};
}]);
<ion-view view-title="Recipes">
<ion-content lazy-scroll>
<ion-refresher on-refresh="doRefresh()"
pulling-text="Pull to refresh..."
refreshing-text="Refreshing!"
spinner="spiral">
</ion-refresher>
<ion-spinner class="ripple spinner-energized" ng-hide="hideIonSpinner"></ion-spinner>
<div class="container" ng-show="showStatusMessage">
<p>{{statusMessage}}</p>
</div>
<div class="recipe" ng-repeat="recipe in recipes | limitTo:limit" >
<div>
<a href="#/app/recipesList/{{recipe._id}}">
<img image-lazy-src="{{recipe.imagePath}}" src="./img/grey.gif" />
<h2>{{recipe.title}}</h2>
</a>
</div>
</div>
</ion-content>
</ion-view>
.factory('RecipesFactory', function($http) {
var Recipes = {};
Recipes.recipesData = [];
Recipes.GetAllRecipes = function() {
return $http.get('http://somethinghost.com:3001/api/recipes/')
.then(function(dataFromServer) {
if (dataFromServer.status === 404) return [];
if (dataFromServer.status === 500) return [];
Recipes.recipesData = dataFromServer.data;
return Recipes.recipesData;
}, function(err) {;
// console.log("inside err");
// console.log("data: " +err.data);
// console.log("headers: " +err.headers);
// console.log("status: " +err.status);
// console.log("config: " + err.config);
Recipes.recipesData = [];
return [];
});
};
return Recipes;
})
.container {
margin: 0 auto;
display: block;
width: 90%;
padding: 0.25rem;
background-color: $stable;
}
.recipe {
display: block;
padding: 1rem 0;
width: 100%;
background-color: transparent;
border-color: 0;
border-style: none;
border-width: 0;
}
.recipe div {
padding: 1rem;
width: 100%;
border-radius: 1rem;
background-color: $light;
}
.container img,
.recipe img {
height: auto;
width: 100%;
vertical-align: baseline;
}
.recipe a {
text-decoration: none;
}
.recipe h2 {
font-size: 20px;
color: $dark;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
margin: 0;
}
@media screen and (min-width: 600px) {
.recipe {
width: 50%;
display: inline-block;
padding: 1rem;
font-size: 12px;
}
}
@media screen and (min-width: 800px) {
.recipe {
width: 33%;
padding: .7rem;
font-size: 10px
}
}
@media screen and (min-width: 1100px) {
.recipe {
width: 25%;
}
}
@media screen and (min-width: 1500px) {
.recipe {
width: 16.7%;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment