Struggling to show dynamic content inside a ngRepeat. When it comes time to show my promise content, I'm getting an empty object {}:
<div ng-controller="DemoCtrl">
<div class="sidebar" ng-repeat="row in rows">
<div class="row">
<input type="checkbox">
<div class="name">{{row.name}}</div>
<div class="title">{{map[$index]}}</div>
</div>
</div>
</div>
and the controller:
function DemoCtrl($scope, $http, $q) {
const rows = function() {
const rows = [];
for (let i = 0; i < 12; i++) {
rows.push({
id: `demo-${i}`,
name: `Demo ${i}`
});
}
return rows;
};
$scope.rows = rows();
$scope.map = [];
// $scope.$watch($scope.map, function (oldValue, newValue) {
// console.log(oldValue, newValue);
// });
function _data() {
// const promises = [];
for (let i = 0; i < $scope.rows.length; i++) {
var defer = $q.defer();
$http.get(`https://jsonplaceholder.typicode.com/posts/${i + 1}`).then(function(post) {
defer.resolve(`${post.data.title.substring(0, 10)}...`);
});
$scope.map.push(defer.promise);
// promises.push(defer.promise);
}
// return $q.all(promises);
return $q.all($scope.map);
}
function _init() {
_data().then(function(data) {
$scope.map = data; // why aren't we getting here?
});
};
_init();
}
Plunker here: https://plnkr.co/edit/2BMfIU97Moisir7BBPNc
I've tinkered with some other ideas such as trying to add a $watch on the $scope object after the value changes, but I'm not convinced this will help in any way. Some lingering questions I have:
From what I understand, you can use a promise inside a template so how/why does this change inside a ngRepeat?
Why isn't my callback for $q.all getting called?
If this is not the right approach, what is?
In Angular you will almost never need to use $q.
You can simply fill an array of posts titles after each $http.get
function DemoCtrl($scope, $http) {
const rows = function () {
const rows = [];
for (let i = 0; i < 12; i++) {
rows.push({
id: `demo-${i}`,
name: `Demo ${i}`
});
}
return rows;
};
$scope.rows = rows();
$scope.map = [];
function _init() {
for (let i = 0; i < $scope.rows.length; i++) {
$http.get(`https://jsonplaceholder.typicode.com/posts/${i + 1}`).then(function (post) {
$scope.map.push(post.data.title);
});
}
}
_init();
}
https://plnkr.co/edit/zOF4KNtAIFqoCOfinaMO?p=preview
Related
I have an array in which the thousands products and i have iterate the array with the help of the ng-repeat,it is working properly in browser,but in the mobile devices products are load really slow so how to improve the performance time of the products on mobile devices.
You should use lazy-load concept. I mean on scroll or on clicking any button, let load some number of rows of data.
For example:
In First API call, load 20 rows, then again 20+20 using API call.
There are lots of modules available like:
See some live examples ngInfiniteScroll
or you can create your own.
.controller('NoticeCtrl', function($scope, $stateParams, $state, $http, NoticeService, baseUrl) {
$scope.items = [];
NoticeService.loadNotice().then(function(items) {
if(items != 0)
{
$scope.items = items;
} else {
$scope.noMoreItemsAvailable = true;
}
});
$scope.noMoreItemsAvailable = false;
$scope.numberOfItemsToDisplay = 5;
$scope.limit = 0;
$scope.loadMore = function(limit) {
var start;
var limit;
var j;
for(var i= limit, j=0; j < $scope.numberOfItemsToDisplay; i++,j++)
{
start = i+ 0;
limit = $scope.numberOfItemsToDisplay;
}
$scope.limit = $scope.limit + $scope.numberOfItemsToDisplay;
NoticeService.refreshNotice(start, limit).then(function(items){
if(items != 0)
{
$scope.items = $scope.items.concat(items);
} else {
$scope.noMoreItemsAvailable = true;
}
$scope.$broadcast('scroll.infiniteScrollComplete');
});
};
})
Factory code
.factory('NoticeService', function($http , $stateParams, baseUrl){
var BASE_URL = baseUrl+"api_method=notice.list&api_version=1.0&app_key=12345&user_id="+$stateParams.userId
var items = [];
return {
loadNotice: function(){
var start = 0;
var limit = 4;
return $http.get(BASE_URL+"&start="+start+"&limit="+limit).then(function(response){
items = response.data.responseMsg;
return items;
});
},
refreshNotice: function(starts, limits){
return $http.get(BASE_URL+"&start="+starts+"&limit="+limits).then(function(response){
items = response.data.responseMsg;
return items;
});
}
}
})
Your HTML part
<ion-item class="content double-padding" style="white-space: normal;" ng-repeat="item in items">
<div class="text-right">{{item.createdAt}}</div>
<h2>{{item.title}}</h2>
{{item.content}}
</ion-item>
<ion-infinite-scroll ng-if="!noMoreItemsAvailable" on-infinite="loadMore(limit)" distance="5%"></ion-infinite-scroll>
I hope this will help you :-)
Its my code:
.controller("GetAllAuthors", function ($scope, $http) {
$http.get('http://localhost:8080/authors')
.then(function (response) {
$scope.authors = response.data;
});
$scope.edit = function (index) {
for (var i = 0; i < $scope.authors.length; i++) {
if ($scope.authors[i].id == index) {
$scope.object = $scope.authors[i];
break;
}
}
}
})
Html view:
<tbody ng-repeat="author in authors">
<td><input type="button" ng-click="edit(author.id)" value="Edit"/></td>
<div ng-controller="GetAllAuthors">
{{object.id}} // <--- doesn't display it
</div>
It's not working. I can't use date binding with my object. How fix it?
You need to put http inside edit method.
.controller("GetAllAuthors", function ($scope, $http) {
$scope.edit = function (index) {
$http.get('http://localhost:8080/authors')
.then(function (response) {
$scope.authors = response.data;
for (var i = 0; i < $scope.authors.length; i++) {
if ($scope.authors[i].id == index) {
$scope.object = $scope.authors[i];
break;
}
}
});
}
})
Try this
Initialize $scope.object outside the function.
Angular loads new pages just by moving the scroll bar. Not when it reaches the bottom. It even loads new posts when i scroll up.
app.factory('Recipes', function ($http) {
var Recipes = function () {
this.recipes = [];
this.loading = false;
this.page = 1;
};
Recipes.prototype.nextPage = function () {
var url = 'api/recipes?page=' + this.page;
if (this.loading) return;
this.loading = true;
$http.get(url)
.success(function (data) {
console.log(this.page);
for (var i = 0; i < data.data.length; i++) {
this.recipes.push(data.data[i]);
}
this.page++;
this.loading = false;
}.bind(this));
};
return Recipes;
});
app.controller('RecipesCtrl', function ($scope, $http, Recipes) {
$scope.recipes = new Recipes();
});
This is the angular part. This is the laravel part:
Route::group(['prefix' => 'api'], function () {
Route::get('recipes', [
'as' => 'recipe.all',
'uses' => 'RecipeController#recipes'
]);});
And this is the html part:
<div ng-controller="RecipesCtrl">
<div class="recipe row" infinite-scroll="recipes.nextPage()" infinite-scroll-distance="1"
infinite-scroll-disabled='recipes.loading'>
<div ng-repeat="recipe in recipes.recipes | orderBy:sortOrder:sortReverse | limitTo:myLimit">
...
</div>
</div>
</div>
First Problem: Why does infinite-scroll load more content constantly?
infinite-scroll-distance is set to 1 in your code. This means that when the element is within 1000 pixels of the browsers bottom the directive will fetch more data.
If you change this to a value closer to 0, the user will have to scroll further for the trigger to get activated.
Second Problem: How do I prevent the directive from loading more content, when there is no more content to return?
One solution to stopping the directive from continuously loading more data is by setting the recipes.loading = true; when the returned data is empty.
As such:
.success(function (data) {
console.log(this.page);
for (var i = 0; i < data.data.length; i++) {
this.recipes.push(data.data[i]);
}
this.page++;
this.loading = false;
recipes.loading = true; // This should prevent more code from being loaded.
}
I have a problem with a new filter which don't receive the data:
here my error log:
Controller Code:
angular.module('reklaApp')
.controller('MainCtrl', function ($scope, $http, Reklas, Modal) {
$scope.newRekla = {};
Reklas.getAll()
.success(function(data) {
$scope.reklas = data;
});
Filter Code:
angular.module('reklaApp')
.filter('dateFilter', function () {
return function (items) {
var filtered = [];
for (var i = 0; i < items.length; i++) {
var item = items[i];
filtered.push(item);
}
return filtered;
};
});
HTML Code:
<tr ng-repeat="rekla in reklas | dateFilter">
<td>{{rekla.dt | date: 'dd.MM.yyyy'}}</td>
<td>{{rekla.order}}</td>
<td>{{rekla.personal}}</td>
<td>{{rekla.department}}</td>
<td>{{rekla.xyz}}</td>
<td>{{rekla.desc | limitTo: '50'}}</td>
<td>{{rekla.costs}}</td>
I think the "item" variable dont receive the data from the ng-repeat!?
It's because you didn't create it to begin with on your $scope. So since your getAll function takes some time the filter doesn't have the data. You can fix this two ways:
By first initializing the variable:
angular.module('reklaApp')
.controller('MainCtrl', function ($scope, $http, Reklas, Modal) {
$scope.newRekla = {};
$scope.reklas = [];
Reklas.getAll()
.success(function(data) {
$scope.reklas = data;
});
Or by updating your filter:
angular.module('reklaApp')
.filter('dateFilter', function () {
return function (items) {
if(!angular.isArray(items)){ return items }
var filtered = [];
for (var i = 0; i < items.length; i++) {
var item = items[i];
filtered.push(item);
}
return filtered;
};
});
I am new to this angular js.
In my code a dropdown control has been loaded with some items, i know this list should be loaded from a xml file.
I want to know where/how it is been coded to load the data. Check this code and help me...
<select size="10" ng-model="model.addSelection" ng-options="a.name for a in availableList | availableList | propertyFilter:model.availableFilter" class="listBoxStyle" wat-focus/>
angular.module('readbackSelectModule', [])
.filter('availableList', [
function () {
return function (input) {
if (!angular.isArray(input)) return input;
var out = [];
for (var i = 0; i < input.length; i++) {
if (input[i].visible == true)
out.push(input[i]);
}
return out;
}
}
])
.filter('plotList', [
function () {
return function (input) {
if (!angular.isArray(input)) return input;
var out = [];
for (var i = 0; i < input.length; i++) {
if (input[i].visible == false)
out.push(input[i]);
}
return out;
}
}
])
.controller('readbackSelectCtrl', ['$scope', '$modalInstance', 'generalDataService', 'keyService', 'propertyFilterFilter', 'availableListFilter', 'plotListFilter', 'plotPanelService',
function ($scope, $modalInstance, generalDataService, keyService, propertyFilterFilter, availableListFilter, plotListFilter, plotPanelService) {
var CANCEL_MESSAGE = 'cancel';
var GET_DATA_MESSAGE = 'getdata';
var REQUEST_PROPERTY_LIST_MESSAGE = 'requestplotdata';
var SUBSCRIBE = 'plotsubscribe';
var UNSUBSCRIBE = 'plotunsubscribe';
var STREAM_TYPE = '4';
$scope.model = {};
$scope.model.addSelection;
$scope.model.removeSelection;
$scope.model.availableFilter;
// List of properties
$scope.availableList = [];
};
Use Angular's $http service.
You can do it in your readbackSelectCtrl, like this:
...
$scope.model = {};
$scope.model.addSelection;
$scope.model.removeSelection;
$scope.model.availableFilter;
$http.get(/** insert XML file URL here **/)
.success(function(data) {
// process the data and extract the XML elements you want
$scope.availableList = xmlExtractedArray;
})
.error(function(err) {
// handle error
});
Check this plunker for a working demo.