Lazy Loading images + Onsenui + angularJs - angularjs

I am currently developing an application that uses Cordova, I use the framework with Onsenui AngularJs and library rn-lazy
My problem is that I try to make my list of image loads, only loads 3 images at once out yet they all charge.
How to ensure that the loading of images is done by 3 of 3 works scroll the phone ?
Template list items
<div ng-controller="QueryRequest">
<div class="loader">
CHARGEMENT
<ons-icon icon="refresh" spin="true"></ons-icon>
</div>
<div data-ng-init="ListItem();">
<ons-list>
<ons-list-item class="topcoat-list__item__line-height ons-list-tweets" ng-repeat=" item in tweets ">
<ons-row class="list-tweet">
<!-- <img ng-src="{{item.Tweet.media_url}}" class="img-response"> -->
<ons-col class="div-image-responsive image-list" ng-click="showLightBox(item.Tweet.media_url)" rn-lazy-background="item.Tweet.media_url" rn-lazy-loaded-class="loaded" rn-lazy-loader="#loader" rn-lazy-loading-class="loading"></ons-col>
<ons-col class="twitter-infos item tabs tabs-secondary tabs-icon-left" size="20">
<ons-button class="btn-custom rating-poll" ng-click="rating('like', item.Tweet.id)" type="large--quiet"></ons-button>
</ons-col>
</ons-row>
</ons-list-item>
</ons-list>
<i class="icon-thumbs-up"></i>
<ons-button class="btn-custom rating-poll" ng-click="rating('dislike', item.Tweet.id)" type="large--quiet"></ons-button>
<i class="icon-thumbs-down"></i>
<ons-button class="btn-custom" ng-click="shareThis(item.Tweet.media_url)" type="large--quiet"></ons-button>
<i class="icon-share"></i>
<p class="tweeter">
<a href="https://twitter.com/{{item.Tweet.username}}" pg-in-app-browser-link="">
#{{item.Tweet.username}}
</a>
</p>
<rating-dialog class="{{modalType}}" show="modalShown" width="100%"></rating-dialog>
<p ng-bind-html="message">{{message}}</p>
</div>
</div>
Controller
App.controller('QueryRequest', function ($scope, $resource, storage, $stateParams, queryRequest, $window, $sce, $rootScope) {
"use strict";
$scope.ListItem = function () {
var request = queryRequest.get();
var tweets = storage.get("twitter_" + request);
if (tweets !== null) {
if (!storage.isObsolete()) {
$scope.tweets = tweets;
} else {
var Tweets = $resource(Clooder.getTweets(request));
Tweets.get({}, function ($query) {
storage.set("twitter_" + request, $query.tweets, 0);
$scope.tweets = storage.get("twitter_" + request);
App.ajaxStop();
});
}
} else {
var Tweets = $resource(Clooder.getTweets(request));
Tweets.get({}, function ($query) {
storage.set("twitter_" + request, $query.tweets, 0);
$scope.tweets = storage.get("twitter_" + request);
App.ajaxStop();
});
}
});

You may have better luck with this library: https://github.com/GeneralElectric/winchjs
Images are loaded based on their own awareness of if they are in the view portal of the screen. There is a lot less (or none) code needed to accomplish your task.

I used jQuery in my AngularJS controller to wait image loading. The following links would help you.
jQuery event for images loaded

Related

working with multiple <video> tags using videojs() function

I am trying to run videos on multiple video tags using videojs but woth no results. I am getting the error TypeError: The element or ID supplied is not valid. (videojs) I am initiating different id properties for each <video> tag based on the id's that they have received through a REST based call.
Should I be having an array of videoplayers instead of one as suggested by other links? Here is my source code:
video.js:
(function () {
'use strict';
angular
.module('controller.video', [])
.controller('Video', ['$scope', 'model', '$sce', function ($scope, model, $sce) {
$scope.ids = [];
$scope.videos = {};
$scope.titles = {};
$scope.specialtyvideos = null;
$scope.likes = {};
$scope.comments = {};
$scope.getVideos = function () {
model.get('specialty', 'Colorectal').then(function (res) {
$scope.specialtyvideos = res.data;
for (var i=0 ; i<$scope.specialtyvideos.length ; i++) {
$scope.videos[$scope.specialtyvideos[i]._id] = $sce.trustAsResourceUrl($scope.specialtyvideos[i].src);
$scope.titles[$scope.specialtyvideos[i]._id] = $scope.specialtyvideos[i].title;
$scope.ids.push($scope.specialtyvideos[i]._id);
}
});
};
$scope.specialtiesVideo = function (id)
{
var element = ""+id;
console.log(id);
console.log(videojs);
var vjs = videojs(id);
vjs.aspectRatio("16:9");
vjs.autoplay(false);
vjs.controls(true);
};
$scope.getLikes = function (id) {
model.get('likes', id).then(function (res) {
$scope.likes[id] = res.data.length;
});
};
$scope.getComments = function (id) {
model.get('comments', id).then(function (res) {
$scope.comments[id] = res.data.length;
});
};
$scope.initialize = function () {
$scope.getVideos();
};
}]);
})();
html file (view using angularjs):
<ion-view id="page17" class=" " ng-controller="Video" ng-init="initialize();">
<ion-content class="has-header">
<div class="list card" ng-repeat="i in ids">
<div class="item item-avatar">
<img src="">
<h2>{{ titles[i] }}</h2>
</div>
<div class="container" ng-init="specialtiesVideo(i)">
<div class="videocontainer">
<video class="video-js" id="{{ i }}" src="{{ videos[i] }}"></video>
</div>
</div>
<div class="item tabs tabs-secondary tabs-icon-left">
<a class="tab-item" href="#">
<i class="icon ion-thumbsup" ng-init="getLikes(i);"></i>
{{ likes[i] }} Likes
</a>
<a class="tab-item" href="#">
<i class="icon ion-chatbox" ng-init="getComments(i);"></i>
{{ comments[i] }} Comments
</a>
<a class="tab-item" href="#">
<i class="icon ion-share"></i>
Share
</a>
</div>
</div>
</ion-content>
</ion-view>
here are the dependencies in the main index html page:
<link href="lib/video.js/dist/video-js.css" rel="stylesheet">
<script src="lib/ionic/js/ionic.bundle.js"></script>
<script src="lib/ngstorage/ngStorage.min.js"></script>
<!-- cordova script (this will be a 404 during development) -->
<script src="js/ng-cordova.min.js"></script>
<script src="cordova.js"></script>
<!-- OTHER REQUIRED DEPENDENCIES-->
<script src="lib/video.js/dist/video.min.js"></script>
<!-- IF using Sass (run gulp sass first), then uncomment below and remove the CSS includes above
<link href="css/ionic.app.css" rel="stylesheet">
-->
<script>
videojs.options.flash.swf = "/lib/video.js/dist/video-js.swf"
</script>
I found the solution to my problem when I realized that my angularjs code was executing much faster than the rendering of the webpage. I used a dynamic array of videojs for each of the many videos that I had to play in a single page. (Though I think a single videojs instance would do).
All I had to do next was to delay the particular function using the $timeout which is a wrapper for window.setTimeout by angularjs.
Here is the code snippet that solve the error:
$scope.specialtiesVideo = function (id)
{
var element = id;
console.log(id);
var confirm = document.getElementById(id);
console.log(document.getElementById(id));
$scope.videoplayers[id] = videojs(id);
console.log("videojs enabled for the video identified by ID :"+id);
$scope.videoplayers[id].aspectRatio("16:9");
$scope.videoplayers[id].autoplay(false);
$scope.videoplayers[id].controls(true);
};
$timeout(function() {
for (var id=0;id < $scope.ids.length;id++) {
$scope.specialtiesVideo($scope.ids[id]);
}
}, 20000);
where 20000 is the number of milliseconds I gave as a window for the page to render and the stack to clear after executions after which I executed the function shown in the code above.

post.length stays 0 due to loop - AngularJS

I'm trying to add pagination but I can't seem to figure out this last part.
Everything is setup, though my pagination isn't recording the amount of posts that are linked with the user.
Seeing that I'm doing a forEach and if loop and pushing the retrieved items into a empty collection, my 'posts.length' is returning 0.
Hence the pagination only showing page 1/1 and not 1/2 (for example).
Here is my full code:
profileCtrl.js
Here is the $http.get - I'm trying to get all the posts that the logged in user made doing this loop:
app.controller('profileCtrl', function($scope, auth, $http, $log) {
$scope.auth = auth;
$scope.date = auth.profile.created_at;
$scope.pageSize = 5;
$scope.posts= [];
$http.get('URL')
.then(function(result) {
angular.forEach(result.data, function(data, key) {
if(data.userId === auth.profile.user_id) {
$scope.posts.push(data);
}
});
});
});
profile.html
As you can see, I'm trying to get the length of post in posts using total-items="posts.length":
<div class="col-md-8 no-padding-right">
<div class="panel panel-primary">
<div class="list-group-item active text-center">
<h4 class="no-margin-top no-margin-bottom">Recent Activity</h4>
</div>
<a href="#" class="list-group-item" ng-repeat="post in posts| startFrom: (currentPage - 1) * pageSize | limitTo: pageSize | orderBy :'created_at':true">
<div class="row">
<div class="col-md-4">
<div class="thumbnail no-border no-margin-bottom">
<img src="https://placehold.it/150x150" alt="bird" width="150" height="150"/>
</div>
</div>
<div class="col-md-8">
<h4 class="no-margin-top no-margin-bottom"><strong>{{post.birdname}}</strong></
</div>
</div>
</a>
<uib-pagination total-items="posts.length" ng-model="currentPage" max-size="pageSize" boundary-link-numbers="true"></uib-pagination>
</div>
</div>
app.js
I also added a filter in app.js:
app.filter('startFrom', function() {
return function(data, start) {
return data.slice(start);
}
});
When I console.log(posts.length); I keep getting 0 and I'm guessing it's because of the $scope.posts = []; declared on top (profileCtrl.js).
Edit:
After doing a bit of debugging with console.log, I do get the value given when doing this:
$http.get('url')
.then(function(result) {
angular.forEach(result.data, function(data, key) {
if(data.userId === auth.profile.user_id) {
$scope.posts.push(data);
}
});
console.log($scope.posts.length);
});
How should I fix this?
If you're waiting for data to be returned before loading the collection (with pagination) either add a ng-if="posts.length" to the container, or initialise $scope.posts as being null and add ng-if="posts" if you want the list to show when the API returns 0 results. This will prevent Bootstrap's pagination directive being parsed until the data it needs is available.
Edit: After debugging, the following plunkr contains a working implementation: http://plnkr.co/edit/VQjNVK6gRKsCqxVb54nR?p=preview

How to show a default image in an array with Ionic

I am working on an Ionic project with the api from the Movie Database. I have this array in an ng-repeat that shows me some images (cast pictures). But not all the images in the array have an actual picture.
Now I am trying to show a default image when the api does not provide an image. My question is how to do this with ng-if i suppose. In my controller I created a scope as followed:
$scope.default_image = '../img/default_poster.png';
Part of my controller:
.controller('MovieDetailCtrl', function($scope, $stateParams, $ionicLoading, MovieService) {
$ionicLoading.show({template: 'Loading ...'});
$scope.init = function(){
MovieService.getCastCrewInfo($stateParams.id).then(function(data){
$scope.casts = MovieService.castMovie;
$scope.default_image = '../img/default_poster.png';
});
$ionicLoading.hide();
}
})
Part of my HTML code:
<div class="content-cast">
<!-- <h3>Cast</h3> -->
<br>
<hscroller>
<ion-scroll direction="x" scrollbar-x="false" >
<hcard ng-repeat="cast in casts" >
<img ng-src="http://image.tmdb.org/t/p/w154/{{cast.profile_path}} || default_image" >
<p class="cast-name">{{cast.name}}</p>
</hcard>
</ion-scroll>
</hscroller>
</div>
Either use a scope function or ng-if
$scope.getImage = function(item){
return item.profile_path ? 'http://image.tmdb.org/t/p/w154/' + item.profile_path : $scope.default_image;
});
View
<img ng-src="{{getImage(cast)}}" >
For ng-if
<img ng-if="cast.profile_path" ng-src="http://image.tmdb.org/t/p/w154/{{cast.profile_path}}">
<img ng-if="!cast.profile_path" ng-src="{{default_image}}">

onsen popover : url not taking variable

Not sure this is an issue with onsen-ui or me being a newbie with angularjs...
I've got a menu with 2 different popover. I wanted to use the same controler since they are similar. The only difference is the button that call it and the page used for the popover menu. So I have something like this
app.controller('PopoverController', function($scope) {
$scope.popurl = function(url) {
$scope.param = url;
};
ons.createPopover($scope.param,{parentScope: $scope}).then(function(popover) {
$scope.popover = popover;
});
$scope.show = function(e) {
$scope.popover.show(e);
};
$scope.destroy = function(e) {
$scope.popover.destroy(e);
};
});
And it gets called this way
<div class="right" ng-controller="PopoverController">
<ons-toolbar-button id="android-share" ng-click="popover.show($event); popurl('popover_share.html')">
<ons-icon icon="ion-android-share" fixed-width="false"></ons-icon>
</ons-toolbar-button>
<ons-toolbar-button id="android-more" ng-click="popover.show($event); popurl('popover.html')">
<ons-icon icon="ion-android-more-vertical" fixed-width="false"></ons-icon>
</ons-toolbar-button>
</div>
This is not working. if I change ons.createPopover($scope.param,{parentScope: $scope}).then(function(popover) by
ons.createPopover('whatever.html',{parentScope: $scope}).then(function(popover) {
Then it works but obviously display whatever.html all the time
So I guess my first question is why is it working when I hardcode the URL and doesn't when I use a variable ?
The second question is : Is there a simpler way to pass my argument to my controler ?
Thank you for your help !
There are two mistakes in your code:
you are trying to show the popover before it has been created.
when you click the toolbar-button you are calling two functions in sequence, without considering that maybe the second function will finish its execution before the first one. This will give an inconsistent result (the popover will be displayed before the new URL will be initialized).
You can solve your issues by creating the popover inside $scope.popurl(), after the URL has been initialized. You can also show the popover after it has been created. Don't forget to destroy the popover after you close it, as any button click will create a new instance of the popover.
HERE you can find a working CodePen example and here is the code:
HTML
<div class="right" ng-controller="PopoverController">
<ons-toolbar-button id="android-share" ng-click="popurl('popover_share.html', $event)">
<ons-icon icon="ion-android-share" fixed-width="false"></ons-icon>
</ons-toolbar-button>
<ons-toolbar-button id="android-more" ng-click="popurl('popover.html', $event)">
<ons-icon icon="ion-android-more-vertical" fixed-width="false"></ons-icon>
</ons-toolbar-button>
</div>
<ons-template id="popover_share.html">
<ons-popover direction="up down" cancelable>
<div style="text-align: center; opacity: 0.5;">
<p>This is "popover_share" popover!</p>
</div>
</ons-popover>
</ons-template>
<ons-template id="popover.html">
<ons-popover direction="up down" cancelable>
<div style="text-align: center; opacity: 0.5;">
<p>This is "popover" popover!</p>
</div>
</ons-popover>
</ons-template>
JS
ons.bootstrap()
.controller('PopoverController', function($scope) {
$scope.popurl = function(url, e) {
$scope.param = url;
ons.createPopover($scope.param, {
parentScope: $scope
}).then(function(popover) {
$scope.popover = popover;
$scope.show(e);
});
};
$scope.show = function(e) {
$scope.popover.show(e);
};
$scope.destroy = function(e) {
$scope.popover.destroy(e);
};
});
Hope it helps!

Dynamic Angular Menu in MVC shared layout file

I have an MVC/Angular project. In the shared MVC _layout file I'm creating a UI menu based on JSON from a Web API call. I'm binding that data in the layout file using angular.
The issue I'm having is when I navigate to a new page MVC reloads the _layout file so the $scope.menu variable in the that file no longer exists so my UI menu disappears. The controller then calls the web API call again and repopulates everything so my UI menu is recreated.
Basically I need a way to keep my menu from being reloaded each time I navigate to a new page. Since I'm new to using angular and MVC together I'm not sure of the best approach. Is there a way to keep my $scope.menu variable from being removed when the shared _layout page is reloaded, can I store the JSON in in sessionStorage and recreate the $scope.menu so my UI menu doesn't disappear?
Any help would be appreciated.
//Angular code that creates the menu in the MVC shared _layout file.
<li class="dropdown" ng-repeat="item in menu" menu-item="item">
<a class="dropdown-toggle" role="button" aria-expanded="false" aria-haspopup="true" href="#" data-toggle="dropdown">{{item.Name}} <span class="caret"></span></a>
<ul class="dropdown-menu">
<li>
<div class="dropdowncontainer">
<div class="row" style="padding: 10px; height: 100%">
<div class="col-md-4 col-lg-4 col-sm-12 no-float box-content right" ng-show="item.Places.length" style="height: 100%">
<h4 style="vertical-align:top">Places</h4>
<ul class="list-unstyled">
<li ng-repeat="plc in item.Places">{{plc.Name}}</li>
</ul>
</div>
//Controller that populates the menu with a web api call
mainModule.controller('navCtrl', function ($scope, dataService, modelService) {
if (!$scope.menu) {
$scope.menu = modelService;
dataService.getJson().then(
function (res) {
angular.copy(res.data, modelService);
},
function () {
alert('Error Loading Navigation !');
}
);
}
});
angular.module('main').value('modelService', []);
angular.module('main')
.factory('dataService', ['$http', function ($http) {
return {
getJson: function () {
return $http.get('web api call');
}
};
}]);

Resources