using ng-repeat with api json in a for-loop - angularjs

I am developing a mini app using angularjs that would grab data from a news api. I have succeeded in getting an array of 10(just the amount i want) articles from the array of 10 news sources( all provided by the api) using a for-loop(below). The problem is that the ng-repeat in the view only displays the last iteration of the loop. How can i get it to display all the iterations?
here is the controller:
angular.module('newsApp',[])
.controller('newsController',['$scope','$http', function($scope,$http){
var index = 0;
var sortby = ['top','latest','popular'];
$http.get('https://newsapi.org/v1/sources?language=en').then(function(response){
var sourceIdArray = [];
var articlesArray = [];
for (var i = 0; i < 9; i++) {
$scope.getId = response.data.sources[i].id;
sourceIdArray.push($scope.getId);
$http.get(' https://newsapi.org/v1/articles?source=' + sourceIdArray[i] + '&apiKey=53bec2b512724f58b92203f0f7e93dc1').then(function(response){
$scope.comits = response.data.articles
articlesArray.push($scope.comits);
});
}
})
}])
The loop gives me all the required articles but i don't know how to write the ng-repeat to display all the data instead of only the last iteration
and the html:
<div class="row rowdiv" ng-repeat="comit in comits" ng-if="$index % 2 == 0">
<div class="col-md-6">
<img ng-src="{{comits[$index].urlToImage}}" alt="">
<h3><a ng-href="{{comits[$index].url}}">{{comits[$index].title}}</a></h3>
<p>{{comits[$index].description}}</p>
<h5>{{result}} {{comits[$index].author}}</h5>
<h6 class="pull-right">{{comits[$index].publishedAt}}</h6>
</div>
<div class="col-md-6">
<img ng-src="{{comits[$index +1].urlToImage}}" alt="">
<h3><a ng-href="{{comits[$index +1].url}}">{{comits[$index +1].title}}</a></h3>
<p>{{comits[$index + 1].description}}</p>
<h5>{{result}} {{comits[$index + 1].author}}</h5>
<h6 class="pull-right">{{comits[$index +1].publishedAt}}</h6>
</div>
</div>
any help would be appreciated!

You are pushing the articles into the articlesArray with articlesArray.push($scope.comits);
You need to make articlesArray a member of $scope, then access it with ng-repeat. $scope.comits only contains the last article retrieved based on your code.
Or declare comits as $scope.comits = [] then change $scope.comits = response.data.articles to $scope.comits.push(response.data.articles)

Related

Problems with `track by $index` with Angular UI Carousel

$index in track by index does not start at zero when pagination is used
I have created a carousel using angular ui bootsrap.
Since am loading so many images(over 1,000), I used a filter to display 500 pictures in the pagination.
.filter('pages', function () {
return function (input, currentPage, pageSize) {
if (angular.isArray(input)) {
var start = (currentPage - 1) * pageSize;
var end = currentPage * pageSize;
return input.slice(start, end);
}
};
})
The controller:
self.currentPage = 1;
self.itemsPerPage = 500;
self.maxSize = 10;
//imagesUrls is response.data from http call
angular.forEach(imagesUrls, function (parent) {
var date = uibDateParser.parse(parent.fileCreationTime, 'M/d/yyyy
hh:mm:ss a');
// fill our slide arrays with urls
// model update here
self.slides.push({
image: parent.fileName,
time: date,
id: parent.id
});
});
self.totalItems = self.slides.length;
And I use it like this:
<div uib-carousel
active="$ctrl.active"
interval="$ctrl.myInterval"
no-wrap="$ctrl.noWrapSlides"
no-pause="true">
<div uib-slide ng-repeat="slide in $ctrl.slides | pages:
$ctrl.currentPage : $ctrl.itemsPerPage track by $index"
index="$index">
<img id="carousel-img" ng-src="{{slide.image}}">
<div class="carousel-caption">
<p>Index {{$index}}</p>
</div>
</div>
</div>
<div class="row">
<ul uib-pagination
total-items="$ctrl.totalItems"
items-per-page="$ctrl.itemsPerPage"
ng-model="$ctrl.currentPage"
max-size="$ctrl.maxSize"
boundary-link-numbers="true"
force-ellipses="true"
class="pagination-sm">
</ul>
</div>
This works as expected.
When the carousel is first loaded, the index is 0. When it moves to the next slide the index is 1, when you move to the next slide the index is 2.
When you display the slide.id of the current image it is also 2.
The problem:
However, when you click the second pagination link, the index does not go back to zero, its starts at the last index the slide was in the carousel.
So now the index is 2 and slide id of the current image is 502.
If you slide till index 20, and you click the pagination link, the index is still at 20. When you display the slide id of the current image it becomes 520.
Is there a way to make the index start at 0 again so the slide.id is 500 and not 502 or 520?
I hope my question is clear.
Avoid track by $index when there is a unique property identifier to work with. When working with objects that are all unique (as is this case), it is better to let ng-repeat to use its own tracking instead of overriding with track by $index.
<div uib-slide ng-repeat="slide in $ctrl.slides | pages:
$ctrl.currentPage : $ctrl.itemsPerPage track by ̶$̶i̶n̶d̶e̶x̶ slide.id"
index="$index">
<img id="{{slide.id}}" ng-src="{{slide.image}}">
<div class="carousel-caption">
<p>Index {{ ̶$̶i̶n̶d̶e̶x̶ slide.id}}</p>
</div>
</div>
From the Docs:
If you are working with objects that have a unique identifier property, you should track by this identifier instead of the object instance. Should you reload your data later, ngRepeat will not have to rebuild the DOM elements for items it has already rendered, even if the JavaScript objects in the collection have been substituted for new ones. For large collections, this significantly improves rendering performance.
— AngularJS ng-repeat Directive API Reference - Tracking
The DEMO
angular.module("app",['ngAnimate', 'ngSanitize', 'ui.bootstrap'])
.controller("ctrl", function(uibDateParser) {
var self = this;
self.currentPage = 1;
self.itemsPerPage = 10;
self.maxSize = 10;
var url = '//unsplash.it/200/100';
var imagesUrls = [];
for (let i=0; i<40; i++) {
var slide = {
fileName: url+"?image="+(1000+i),
id: 'id'+(0+i+100),
fileCreationTime: new Date()
}
imagesUrls.push(slide);
}
self.slides = [];
//imagesUrls is response.data from http call
angular.forEach(imagesUrls, function (parent) {
var date = uibDateParser.parse(parent.fileCreationTime,
'M/d/yyyy hh:mm:ss a');
// fill our slide arrays with urls
// model update here
self.slides.push({
image: parent.fileName,
time: date,
id: parent.id
});
});
//console.log(self.slides);
self.totalItems = self.slides.length;
})
.filter('pages', function () {
return function (input, currentPage, pageSize) {
if (angular.isArray(input)) {
var start = (currentPage - 1) * pageSize;
var end = currentPage * pageSize;
return input.slice(start, end);
}
};
})
<script src="//unpkg.com/angular/angular.js"></script>
<script src="//unpkg.com/angular-animate/angular-animate.js"></script>
<script src="//unpkg.com/angular-sanitize/angular-sanitize.js"></script>
<script src="//unpkg.com/angular-ui-bootstrap/dist/ui-bootstrap-tpls.js"></script>
<link href="//unpkg.com/bootstrap/dist/css/bootstrap.css" rel="stylesheet">
<body ng-app="app" ng-controller="ctrl as $ctrl">
<div class="container" uib-carousel
active="$ctrl.active"
interval="$ctrl.myInterval"
no-wrap="$ctrl.noWrapSlides"
no-pause="true">
<div uib-slide ng-repeat="slide in $ctrl.slides | pages:
$ctrl.currentPage : $ctrl.itemsPerPage track by slide.id"
index="$index">
<img id="{{slide.id}}" ng-src="{{slide.image}}">
<div class="carousel-caption">
<p>Index {{slide.id}}</p>
</div>
</div>
</div>
<div class="row container">
<ul uib-pagination
total-items="$ctrl.totalItems"
items-per-page="$ctrl.itemsPerPage"
ng-model="$ctrl.currentPage"
max-size="$ctrl.maxSize"
boundary-link-numbers="true"
force-ellipses="true"
class="pagination-sm">
</ul>
</div>
</body>

Angularjs - Accumulate the results of the pagination

I have a paginate layer showing the results to ten a ten:
<div class="panel-body" ng-repeat="user in users">
<div class="col-md-12">
<div class="col-md-6 name">{{user.dato1}}</div>
<div class="col-md-6 product">{{user.dato2}}/div>
</div>
<div class="col-md-12 pos-action">
<div class="col-md-4 product">{{user.dato3}}</div>
<div class="col-md-8 product">{{user.dato4}}</div>
</div>
</div>
I need the following: The first page show ten results, but if I go to the next page I have to show the new ten results and the ten the previous results and so on, for example, the page size three must have thirty registers, but if I come back the page size one must show only ten.
/*
* Function to get data service.
*/
function paintData()
{
dataIn=getListEventsPdtes.dataIn;
dataOut=getListEventsPdtes.dataOut;
if(dataOut.listEvents != null ){
$scope.users = dataOut.listEvents.event;
//Save data in cache
$scope.cache=$scope.cache.concat(dataOut.listEvents.event);
}else{
var text = "An internal error occurred, please contact your system administrator";
modalFactory.message(text);
}
}
function prevPage(){
if($scope.currentPage > 0){
$scope.currentPage--;
var cachedValues = $scope.cache.slice($scope.currentPage*$scope.itemsPerPage, $scope.currentPage*$scope.itemsPerPage+$scope.itemsPerPage);
$scope.users = cachedValues;
}
};
function nextPage(dato, repo){
$scope.currentPage++;
var cachedValues = $scope.cache.slice($scope.currentPage*$scope.itemsPerPage, $scope.currentPage*$scope.itemsPerPage+$scope.itemsPerPage);
if(cachedValues.length == 0){
$scope.getData(dato, repo);
}else{
$scope.users = cachedValues;
}
};
Thanks,
Can u pass the index value to PrevPage when click on paging index 1 2....
function prevPage(index){
if($scope.currentPage > 0){
$scope.currentPage--;
var cachedValues = $scope.cache.slice(index*$scope.itemsPerPage, index*$scope.itemsPerPage+$scope.itemsPerPage);
$scope.users = cachedValues;
}
};

AngularJS ng-attr not working when used with a tag with a dash

I am trying to generate a JS Chart with a value from a $scope but the value does not get updated in that specific tag because it has a dash in it, it works perfectly when I tested it in the div above to replace the width's value of 100 with the $scope and it works but just not with this specific tag. Any ideas?
HTML
<div class="col-md-12 col-sm-12 col-xs-6" ng-controller="HomeCtrl">
<div>
<p>Option1</p>
<div class="">
<div class="progress progress_sm" style="width: 100%;">
<div class="progress-bar bg-green" role="progressbar" ng-attr-data-transitiongoal="{{total | number:0}}"></div>
</div>
</div>
</div>
</div>
This is the code from the controller, the server code for the route (for pulling data from MongoDB) works perfectly because I was able to pull the data and I have been able to use console.log() to print in the route as well:
Script
function HomeCtrl($scope, $http, $filter) {
$scope.total = 0;
var refresh = function() {
$http.get("/homelist").success(function(response) {
$scope.homelist = response;
var homelista = $scope.homelist;
for (var i = 0; i < homelista.length; i++) {
var donedeals = homelista[i];
$scope.total += (Number(donedeals.hgtgt));
}
};
refresh();
}
}
More importantly I am able to use the data in the js file with other html tags, so the server or the controller is not the problem at all but it is either a bug with Angular or something I am missing with the html tag.

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

Populate a select list with AngularJS from a response in JSON

I would like to download a response on a server in JSON which contains the attribute to populate my select list. I would like to do it with AngularJS and I'm using Angular 2.
Nothing appears, I think the problem is on my attribute ng-repeat :
<div id="myDiv">
<div ng-app="d3DemoApp">
<div ng-controller="AppCtrl">
<div ng-repeat="n in filters track by $index">
{{n}}
</div>
</div>
</div>
</div>
This is my controller :
angular.module('d3DemoApp',[])
.controller('myCtrl',function($scope) {
$scope.notes = userService.getData();
//Create and append select list
var selectList = document.createElement("select");
selectList.setAttribute("id", "releaseFilter");
myDiv.appendChild(selectList);
selectList.setAttribute("class", "form-control");
selectList.setAttribute("onclick", "myFunction()");
//Create and append the options
for (var i = 0; i < $scope.notes.length; i++) {
var option = document.createElement("option");
option.setAttribute("value", array[i]);
option.text = $scope.notes[i];
selectList.appendChild(option);
}
});
This is the service which should download the response :
app.service("userService",["$http",
function($http) {
_this = this;
this.getData = function() {
},
$http.get('./dataOnServer.json'). // This adress is normally an HTTP adress which send me the JSON
success(function(data) {
return data;
});
}
]);
This is an online example of the problem with Plunker : https://plnkr.co/edit/du7sU8bhg2G3X7HckbV9?p=preview
I hope you will can help me, thanks a lot !
I would point out that you are repeating filters when you are not defining such variable in your scope or anywhere? You should probably repeat $scope.notes so it would go like this:
<div id="myDiv">
<div ng-app="d3DemoApp">
<div ng-controller="AppCtrl">
<div ng-repeat="n in notes track by $index">
{{n}}
</div>
</div>
</div>
</div>
EDIT:
And you can do a select like this:
<select>
<option ng-repeat="n in notes">{{n.value}}</option>
</select>
And your JSON is invalid. It should be like this for the repeat:
[{value: "value 1"},{value: "value 2"},{value: "value 3"}]

Resources