Alternative of ng-repeat in the AngularJS? - angularjs

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 :-)

Related

Showing dynamic content inside ngRepeat

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

Highcharts send global data to angular controller

I've recently decided to use angular on a webpage, but having never used it before and being new to web dev I've run into some issues. The page has some highchart graphs where, upon clicking on a point triggers a modal with a table of data. This table is created with an angular controller.
Initially the table is empty because the user hasn't selected the data to populate it. So the data called: cases starts:var cases = []; and the controller initializes with: $scope.items = cases;
Here is where I get the data for the table:
plotOptions: {
series: {
cursor: 'pointer',
point: {
events: {
click: function () {
if (this.series.name == 'Work left')
{
cases = [];
//GET THE DATA
$.getJSON(uri + '/get?team=' + team + '&sprint=' + sprint + '&day=' + this.category)
.done(function (data) {
$.each(data, function (n, field) {
n++
cases.push({ "DT": field.dt, "Title": field.subject, "Type": field.type, "Est": field.est, "Product": field.Prod, "Sprint": field.Sprint, "Status": field.Status, "CreatedDate": field.cDate });
});
});
//UPDATE THE TABLE WITH NEW DATA HERE
$("#myModal").modal();//TRIGGER MODAL
}
}
}
}
}
}
In this highchart function I get the parameters: team,sprint and day based off of which point on which graph the user clicked. Then get the data from an api call.
What I want to know is if it's possible to "reinitialize" the angular controller at //UPDATE THE TABLE WITH NEW DATA HERE line, before triggering the modal. I need $scope.items = cases; but with cases being populated with the new data.
Basically I get the data dynamically with a highchart function, and I want to send this data to the angular controller where the table is updated, so that when I trigger the modal the table on it has the specified data.
Angular table controller:
var sortingOrder = 'CreatedDate'; //default sort
var app = angular.module("casetable", []);
app.controller('initApp', ['$scope', '$filter',
function ($scope, $filter) {
// init
$scope.sortingOrder = sortingOrder;
$scope.reverse = false;
$scope.filteredItems = [];
$scope.groupedItems = [];
$scope.itemsPerPage = 9;
$scope.pagedItems = [];
$scope.currentPage = 0;
$scope.items = cases;
var searchMatch = function (haystack, needle) {
if (!needle) {
return true;
}
return haystack.toLowerCase().indexOf(needle.toLowerCase()) !== -1;
};
// init the filtered items
$scope.search = function () {
$scope.filteredItems = $filter('filter')($scope.items, function (item) {
for (var attr in item) {
if (searchMatch(item[attr], $scope.query))
return true;
}
return false;
});
// take care of the sorting order
if ($scope.sortingOrder !== '') {
$scope.filteredItems = $filter('orderBy')($scope.filteredItems, $scope.sortingOrder, $scope.reverse);
}
$scope.currentPage = 0;
// now group by pages
$scope.groupToPages();
};
// show items per page
$scope.perPage = function () {
$scope.groupToPages();
};
// calculate page in place
$scope.groupToPages = function () {
$scope.pagedItems = [];
for (var i = 0; i < $scope.filteredItems.length; i++) {
if (i % $scope.itemsPerPage === 0) {
$scope.pagedItems[Math.floor(i / $scope.itemsPerPage)] = [$scope.filteredItems[i]];
} else {
$scope.pagedItems[Math.floor(i / $scope.itemsPerPage)].push($scope.filteredItems[i]);
}
}
};
$scope.deleteItem = function (idx) {
var itemToDelete = $scope.pagedItems[$scope.currentPage][idx];
var idxInItems = $scope.items.indexOf(itemToDelete);
$scope.items.splice(idxInItems, 1);
$scope.search();
return false;
};
$scope.range = function (start, end) {
var ret = [];
if (!end) {
end = start;
start = 0;
}
for (var i = start; i < end; i++) {
ret.push(i);
}
return ret;
};
$scope.prevPage = function () {
if ($scope.currentPage > 0) {
$scope.currentPage--;
}
};
$scope.nextPage = function () {
if ($scope.currentPage < $scope.pagedItems.length - 1) {
$scope.currentPage++;
}
};
$scope.setPage = function () {
$scope.currentPage = this.n;
};
// functions have been describe process the data for display
$scope.search();
// change sorting order
$scope.sort_by = function (newSortingOrder) {
if ($scope.sortingOrder == newSortingOrder)
$scope.reverse = !$scope.reverse;
$scope.sortingOrder = newSortingOrder;
};
}]);

AngularJS custom filter don't receive data

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;
};
});

AngularJS paging

I made AngularJS pagination with spring mvc It works well ,but the application get a large amount of data from database so the application is very slow when I get first page because it get all records,Can anyone help me to solve this problem?I want to get subset of data from database depending on angularJS pagination
Spring mvc Controlller
#RequestMapping(value = "/rest/contacts",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public List<Contact> getAll() {
return contactRepository.findAll();
}
AngularJS Service
pagingpocApp.factory('Contact', function ($resource) {
return $resource('app/rest/contacts/:id', {}, {
'query': { method: 'GET', isArray: true},
'get': { method: 'GET'}
});
});
AngularJS Controller
pagingpocApp.controller('ContactController', function ($scope, $filter,resolvedContact, Contact, resolvedRole) {
$scope.contacts = resolvedContact;
var sortingOrder = 'firstName';
$scope.sortingOrder = sortingOrder;
$scope.reverse = false;
$scope.filteredItems = [];
$scope.groupedItems = [];
$scope.itemsPerPage = 10;
$scope.pagedItems = [];
$scope.currentPage = 0;
var searchMatch = function (haystack, needle) {
if (!needle) {
return true;
}
return haystack.toLowerCase().indexOf(needle.toLowerCase()) !== -1;
};
// init the filtered items
$scope.search = function () {
$scope.filteredItems = $filter('filter')($scope.contacts, function (item) {
for(var attr in item) {
if (searchMatch(item[attr], $scope.query))
return true;
}
return false;
});
// take care of the sorting order
if ($scope.sortingOrder !== '') {
$scope.filteredItems = $filter('orderBy')($scope.filteredItems, $scope.sortingOrder, $scope.reverse);
}
$scope.currentPage = 0;
// now group by pages
$scope.groupToPages();
};
// calculate page in place
$scope.groupToPages = function () {
$scope.pagedItems = [];
for (var i = 0; i < $scope.filteredItems.length; i++) {
if (i % $scope.itemsPerPage === 0) {
$scope.pagedItems[Math.floor(i / $scope.itemsPerPage)] = [ $scope.filteredItems[i] ];
} else {
$scope.pagedItems[Math.floor(i / $scope.itemsPerPage)].push($scope.filteredItems[i]);
}
}
};
$scope.range = function (start, end) {
var ret = [];
if (!end) {
end = start;
start = 0;
}
for (var i = start; i < end; i++) {
ret.push(i);
}
return ret;
};
$scope.prevPage = function () {
if ($scope.currentPage > 0) {
$scope.currentPage--;
}
};
$scope.nextPage = function () {
if ($scope.currentPage < $scope.pagedItems.length - 1) {
$scope.currentPage++;
}
};
$scope.setPage = function () {
$scope.currentPage = this.n;
};
// functions have been describe process the data for display
$scope.search();
// change sorting order
$scope.sort_by = function(newSortingOrder) {
if ($scope.sortingOrder == newSortingOrder)
$scope.reverse = !$scope.reverse;
$scope.sortingOrder = newSortingOrder;
// icon setup
$('th i').each(function(){
// icon reset
$(this).removeClass().addClass('icon-sort');
});
if ($scope.reverse)
$('th.'+new_sorting_order+' i').removeClass().addClass('icon-chevron-up');
else
$('th.'+new_sorting_order+' i').removeClass().addClass('icon-chevron-down');
};
});
One quick option would be to create a get method on your API that only returns a subset of the data, maybe only 25 contacts at a time, or a page or two worth of data. Then you could create a service in angular that makes that get call every 3 seconds or so to get the next 25 contacts. A sort of lazy loading technique.
Ben Nadel does a great job in this article of outlining how his company handles large sets of images being loaded to a page using a lazy loading technique. Reading through his example could give you a nice starting point.
Edit: I'm also going to recommend you refer to this solution for an answer slightly more on point to what you're looking to achieve. He recommends pushing data to your controller as soon as it's found:
function MyCtrl($scope, $timeout, $q) {
var fetchOne = function() {
var deferred = $q.defer();
$timeout(function() {
deferred.resolve([random(), random() + 100, random() + 200]);
}, random() * 5000);
return deferred.promise;
};
$scope.scans = [];
for (var i = 0; i < 2; i++) {
fetchOne().then(function(items) {
angular.forEach(items, function(item) {
$scope.scans.push(item);
});
});
};
}

Load data to dropdown in angularjs

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.

Resources