post.length stays 0 due to loop - AngularJS - 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

Related

Angularjs delay append new data and display old data 1s

It delays append new data and display old data 1s when I click: https://youtu.be/KeqRdGueekg
In controller:
myApp.controller('Notebook', function($scope, $http){
//Display Note click NoteBook
$scope.xl_note = function(id){
$http.get("/thunder_note/notebooks/show_note?id=" + id)
.then(function(response) {
$scope.dataNote = response.data;
});
};
});
In view:
<div class="modal-body">
<div class="list_body list_body_note_of_notebook">
<div class="list_content show_noteaas" ng-repeat="data in dataNote.Note">
<a href="/thunder_note/notes/note_detail/{{data.id}}" style="text-decoration: none;">
<p class="title">{{data.title}}</p>
</a>
</div>
</div>
</div>
when you call /thunder_note/notes/note_detail/
you do 2 things calling api and redirecting page
the page ridects immidiate so there is allready old data
but api response takes some time for getting response
so clear $scope.dataNote =""; before your calling api

How to limit results with ng-repeat?

Sorry for the basic question, extremely new to software development and angular in particular. I'm currently making a small app that uses an api to find cinemas near a certain postcode.
I have made a results page that show what films are playing in a certain cinema, but I want to limit the amount of results returned and include a 'Show more films' button.
I have included my html and controller below:
HTML
<div class="main-container">
<fountain-header></fountain-header>
<div class="cinemas-container">
<h2 align="center" class="cinemas-h2">Movies playing here:</h2>
<div class="cinema2" ng-repeat="listing in $ctrl.listings">
<h3 class="cinema-h5">{{listing.title}}</h3>
<ul class="cinema-h4">
<li ng-repeat="time in listing.times">{{time}}</li>
</ul>
</div>
<div class="main-container">
</main>
</div>
<fountain-footer></fountain-footer>
</div>
</div>
ListingsController
function ListingsController($http, $stateParams) {
console.log($stateParams);
console.log($stateParams.cinemaID);
var vm = this;
$http
.get('https://api.cinelist.co.uk/get/times/cinema/' + $stateParams.CinemaID +'?day=1')
.then(function (response) {
console.log(response);
vm.listings = response.data.listings;
});
}
Could I just use limitTo to achieve this?
P.S sorry for the poor information, it's my first question on here.
Please try the following example in the fiddle link -
Using the limitTo filter.
ng-repeat="d in data | limitTo: limitvar"
https://jsfiddle.net/m0q9ju8a/
let me know if this helps.
You can do like this:
HTML
<div class="main-container">
<fountain-header></fountain-header>
<div class="cinemas-container">
<h2 align="center" class="cinemas-h2">Movies playing here:</h2>
<div class="cinema2" ng-repeat="listing in vm.listings | limitTo: vm.limit as results">
<h3 class="cinema-h5">{{listing.title}}</h3>
<ul class="cinema-h4">
<li ng-repeat="time in vm.listing.times">{{time}}</li>
</ul>
</div>
<button ng-hide="results.length === vm.listings.length" ng-click="vm.limit = vm.limit +8">show more...</button>
<div class="main-container">
</main>
</div>
<fountain-footer></fountain-footer>
</div>
</div>
and in youn controller
function ListingsController($http, $stateParams) {
console.log($stateParams);
console.log($stateParams.cinemaID);
var vm = this;
vm.limit = 8;
$http
.get('https://api.cinelist.co.uk/get/times/cinema/' + $stateParams.CinemaID +'?day=1')
.then(function (response) {
console.log(response);
vm.listings = response.data.listings;
});
}

Nested ng-repeat with different data

I am using AngularJS v1.5.0 in my web application. I have feedbacks of the users which are displayed using ng-repeat. Now whenever the executive clicks on the feedback, I make a server call and fetch the history of user and show it on the panel.
Once the call is successful, I assign the data to the feebackDetails variable which is now the controller scope variable. But I dont want it to have the controller scope, as each feedback will have different user and different data.
<div class="tab-pane fade in" ng-controller="controller-feedback" id="feedback">
<div class="col-md-12">
<div class="row">
<div ng-repeat="feedback in feedbacks track by $index" ng-click="getUserHistory(feedback.userId)" data-toggle="collapse" data-target="#feedback{{$index}}" aria-expanded="false" aria-controls="#feedback{{$index}}">
<div class="alert alert-info">
<div>{{feedback.feedback}}</div>
<div class="collapse" id="feedback{{$index}}">
<div class="well">
<div ng-repeat="feedbackDetail in feedbackDetails track by $index">
<span style="font-weight: bold">Question:</span> {{feedbackDetail.question}} <br>
<span style="font-weight: bold">Answer:</span> {{feedbackDetail.answer}} <br>
<span style="font-weight: bold">Helpful:</span> {{feedbackDetail.helpful}} <br>
<span style="font-weight: bold">Feedback:</span> {{feedbackDetail.feedback}} <br>
<span style="font-weight: bold">Executive:</span> {{feedbackDetail.executive}} <br>
<hr ng-hide="$last">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
This is my controller part.
app.controller('controller-feedback', function ($scope, $http, $rootScope) {
$scope.feedbacks = [];
$scope.feedbackDetails = [];
// This will get the feedbacks
$http
.get(phpUrl + 'test-feedback', {params:{doctorId:doctorId}})
.then(function success(response) {
$scope.feedbacks = response.data.data;
$rootScope.feedbackCount = response.data.data.length.toString();
}, function error(success) {
});
$scope.getUserHistory = function(userId) {
console.log(userId);
$http
.get(phpUrl + 'test-feedback-details', {params:{userId:userId}})
.then(function success(response) {
/**
* This variable $scope.feedbackDetails must be different for each ng-repeat
*/
$scope.feedbackDetails = response.data;
}, function error(success) {
});
};
});
change getUserHistory to accept feedback object.
$scope.getUserHistory = function(feedback) {
var userId = feedback. userId ....
and rather than
$scope.feedbackDetails = response.data;
assign
$scope.feedback.feedbackDetails = response.data;
Inner ng-repeat should use feedback.feedbackDetails.
You could create a directive called feedbackDetail that you put inside your ng-repeat which uses an isolate-scope and you pass in your feedbackDetail from the ng-repeat.
Then when you make the HTTP request from the directives controller and assign it to $scope it would be a scope for just that part of the repeat.

Data can not be synchronized using angularjs

I store a data in a factory like this:
module.factory('AddedStockListData', function(){
var list= [];
var size = 0;
return{
getList: function(){
return list;
},
setList: function(data){
list = data;
},
getSize:function(){
return size;
},
setSize:function(){
size++;
},
setDelSize:function(){
size--;
}
}
});
And in my controller the code as follows:
$scope.stocksSearchList = AddedStockListData.getList();
$scope.load = function($done){
$timeout(function() {
document.getElementById("showTipsToDropDown").style.display = "none";
$scope.stocksSearchList = AddedStockListData.getList();
$done();
}, 500);
}
My html like this:
<ons-page ng-controller="createPortStockController">
<ons-pull-hook ng-action="load($done)" var="loader" id="pullDown">
<span ng-switch="loader.getCurrentState()">
<span ng-switch-when="initial"><ons-icon size="35px" icon="ion-arrow-down-a"></ons-icon> Pull down to refresh</span>
<span ng-switch-when="preaction"><ons-icon size="35px" icon="ion-arrow-up-a"></ons-icon> Release to refresh</span>
<span ng-switch-when="action"><ons-icon size="35px" spin="true" icon="ion-load-d"></ons-icon> Loading data...</span>
</span>
</ons-pull-hook>
<div>
<ons-toolbar class="DCF" fixed-style>
<div class="left">
<ons-back-button style="color:white;"></ons-back-button>
</div>
<div class="center" style="font-size:22px;" >Create Portfolio</div>
<div ng-click="create()"class="right" style="font-size:18px;color:white;margin-top:10px;padding-right:10px;" >Create</div>
</ons-toolbar>
<div class="addStockButton" ng-click = "myNavigator.pushPage('portStockSearchList.html', { animation : 'slide'})">
<i class="fa fa-plus" ></i>Add Stock
<p id="showTipsToDropDown"style="margin:0px;font-size:12px;text-align:center;color:#adadad;">After your first time add stocks, please drop down to refresh</p>
</div>
<div class="stockSearchList">
<div ng-repeat="stockSearch in stocksSearchList">
<div class="stockSearchOne">
<div class="stockSearchOneComp">{{stockSearch.company}}</div>
<div class="stockSearchOneInfo">Symbol: {{stockSearch.symbol}} | Exchange:{{stockSearch.exchange}} </div>
</div>
</div>
</div>
</div>
Actually, I change the factory data in next page,I want to make this page change the display while the factory data is changed.
But the result is , at the first time I change the data in the next page and back to this page, the data will not display, and I will refresh this page by use the ons-pull-hook> and then if I go to the next page to change the data, when I back to here, data will be synchronized display .
So the result is at the first time , I have to refresh the page to get the data, but after the first time, I don't need to do this
Anybody can help me to solve this problem?
Try using $scope.$apply() after the data have been fetched, it should update the content without any need to refresh the page. You can learn more about $scope.$apply() here.

AngularJs how to reload a template page after selecting a charater

I am using http.get and i need to reload a template after selecting a character so that my template gives the answer according to what I selected
The code of the template
<div class="container-fluid" ng-controller="CriterioCtrl">
<div id="result"></div>
<div>
Selected Items:
<div ng-repeat="id in selection">
{{id}}
</div>
</div>
<div ng-repeat-start="crit in data" class="row">
<h2 align="center">{{crit.name}}</h2>
<div ng-repeat="caracter in crit.characters" class="col-md-4">
<div type="checkbox" value="{{caracter.id}}" ng-checked="selection.indexOf(caracter.id) > -1" ng-click="clickSelection(caracter.id)">
<a href="#crit" class="thumbnail" ng-click="clickCriterios(caracter.id)">
<h4 align="center">{{caracter.name}}</h4>
<img ng-src="http://skaphandrus.com/{{caracter.image_url}}"/>
</a>
</div>
</div>
</div>
<div ng-repeat-end>
</div>
<!--<button class="btn" ng-click="toggle()">Toggle</button>
<p ng-show="visible">Hello World!</p> codigo de um botao -->
</div>
This code is for the selection
$scope.selection=[];
$scope.clickSelection = function clickSelection(caracterId) {
var idx = $scope.selection.indexOf(caracterId);
// is currently selected
if (idx > -1) {
$scope.selection.splice(idx, 1);
}
// is newly selected
else {
$scope.selection.push(caracterId);
}
var selectedId = $scope.selection;
console.log(selectedId);
// Check browser support
if (typeof(Storage) != "undefined") {
// Store
localStorage.setItem("idSelect", selectedId);
// Retrieve
document.getElementById("result").innerHTML = localStorage.getItem("idSelect");
}
};
This code is the http part in another controller
MyApp.controller('EspeciesCtrl', function ($scope, $http) {
$http({
url: 'someurl',
method: "post",
params: {module_id: localStorage.getItem("idMod"),"characters[]": [localStorage.getItem("idSelect")]}
})
.then(function(res){
$scope.data = res.data;
});
});
This is the code of the template that have to change after the selection
<div class="container-fluid" ng-controller="EspeciesCtrl">
<div class="row">
<div ng-repeat="esp in data" class="col-md-6">
<a href="#infEsp" class="thumbnail" ng-click="clickEspecie(esp.id)">
<h4 align="center">{{esp.name}}</h4>
<img ng-src="{{esp.image_src}}"/>
</a>
</div>
</div>
</div>
How can i do that?
edit 1
If I've correctly understood, you may need to use ng-show (https://docs.angularjs.org/api/ng/directive/ngShow) whose boolean value checks if the user selected anything and show the extra bit of code you need, instead of trying to have another http request.
Also, it seems like you are using $scope.data for both the esp and the crit, so you will end up with the errors.
You probably don't need to reload the template.
You may want to use the data in $scope.data inside the template in order to let Angular manage the update on the view. As soon as the $scope.data changes, the rendered HTML changes too.
I can't comment but it would be helpful if you could share the template you are using and be more specific in your request :)

Resources