Delay in ng-repeat - angularjs

How can I insert delay between every ng-repeat iterations so my table will generate records slower. Is there any way to do it without using ngAnimate.
<table>
<tr ng-repeat="x in records">
<td>{{x}}</td>
</tr>
</table>

[Suggestion]
If you data is loading slow, maybe is because you have duped keys, so for test it you can try with track by $index like this
<table>
<tr ng-repeat="x in records track by $index">
<td>{{x}}</td>
</tr>
</table>
[Solution ]
If you still want to control the interaction of ng-repeat, it is best to create a dynamic variable that is manipulated as time passes, then you can have a primary array with all records
$scope.records = [
{
"name": "name1",
"data2": "data2.1",
"data3": "data3.1"
},
{
"name": "name2",
"data2": "data2.2",
"data3": "data3.2"
},
{
"name": "name3",
"data2": "data3.3",
"data3": "data3.3"
}
];
Then you could use setTimeout to call a function that passes data from the primary array to another final array, an index per interaction
//start to proccess
setTimeout(function(){$scope.Result();},1000);
//Here pass data from Records to FinalResult in each interaction
$scope.Result=function(){
dif=$scope.records.length-$scope.FinalResult.length;
currentRow=$scope.FinalResult.length;
if(dif>0){
$scope.FinalResult.push($scope.records[currentRow]);
}
if($scope.records.length>$scope.FinalResult.length){
setTimeout(function(){$scope.Result();},1000);
}else{
console.log('Finish Load');
$scope.FinishRender=true;
}
//refresh
$scope.$apply();
}
And finally deliver this variable with another function...
//get the finish Array
$scope.getFinalResult=function(){
return $scope.FinalResult;
}
and HTML
<body>
<div ng-controller="recordsCtrl">
<table style="border:1px solid black">
<tr ng-repeat="x in getFinalResult()">
<td>{{x.name}}</td>
<td>{{x.data2}}</td>
<td>{{x.data3}}</td>
</tr>
</table>
<div ng-if="FinishRender" style="color:red;font-weight:bold">Data Loaded!!!</div>
</div>
</body>
Please feel free to check a solution in punkler
[Optional]
Also you could use a directive to control the last interaction like this
myApp.directive('onFinishRender', function ($timeout) {
return {
restrict: 'A',
link: function (scope, element, attr) {
console.log(element);
if (scope.$last === true) {
console.log('Finish Load');
}
}
}
});
and html
<table>
<tr ng-repeat="x in getFinalResult()" on-finish-render="onFinishRender">
....
...
</tr>
</table>
note:I'm not really sure but I think it's possible to capture every interaction with this method

A possible solution in your situation could be to take the source array and populate the ng-repeat array in increments with a delay using _.chunk and $timeout, as such:
index.html
<table>
<tr ng-repeat="x in records track by $index">
<td>{{x}}</td>
</tr>
</table>
appCtrl.js
$scope.sourceData = [data, data, data];
$scope.records = [];
/**
*#param source (array): the array with the data used to populate the ng-repeat array
*#param target (array): the array to which ng-repeat points
*#param delay (integer): the render delay, in milliseconds
*#param renderSize (integer): the amount of list items to render between each delay
*
**/
function delayedRender(source, target, delay, renderSize) {
var promise = $q.resolve();
function scheduleRender(partial) {
Array.prototype.push.apply(target, partial);
// the timeout will ensure that your next render won't occur before the delay
return $timeout(function(){}, delay);
}
// _.chunk is a Lodash function that takes an array and chops it into smaller chunks.
// 'renderSize' is the size of these chunks.
var partials = _.chunk(source, renderSize);
var next;
// here we schedule renders to occur only after
// the previous render is finished through the use of $q promises
_.forEach(partials, function(partial) {
next = scheduleRender.bind(null, partial);
promise = promise.then(next);
});
}

Related

Bind data from pagination to filter in Angular

I have a simple pagination with letters:
<div ng-controller="DataController">
<ul class="pagination">
<li ng-repeat="letter in data_letters">
{{letter}}
</li>
</ul>
<table class="table table-striped">
<tbody>
<tr>
<th>Name</th>
<th>State</th>
</tr>
<tr ng-repeat="person in persons | startsWithLetter:letter">
<td>{{person.Name}}</td>
<td>{{person.State}}</td>
</tr>
</tbody>
</table>
</div>
What is the easiest way to bind the letter (on which we clicked at the paginaton) to the table filter.
Here is a fully functional plunkr: http://plnkr.co/edit/Trr5LzrcMfZqonD0jvjX?p=preview
I have everything implemented already. It is just the data-binding which is missing. Any ideas?
One issue with your code is that you are unnecessarily injecting $scope into your filter:
app.filter('startsWithLetter', function($scope) {
should be
app.filter('startsWithLetter', function() {
The other issue is using 'C-D' as a filter value. I would change $scope.data_letters to be an array of objects that contain a key/value pair like this:
$scope.data_letters = [{
key: 'A',
value: "A"
}, {
key: "B",
value: "B"
}, {
key: ['C', 'D'],
value: "C-D"
}];
Then change your check in the filter to evaluate all keys, like this:
angular.forEach(letters, function(letter, key) {
if (itemName.startsWith(letter)) {
filtered.push(items[i]);
}
});
You can see it working here where I forked your plunk.
Updated your plunk here
Problem was that your filter was not recognized by angular.
Also, I would suggest using
Chrome Developer Tools
it shows useful debug information
app.filter('startsWithLetter', function() {
console.log("Inside startsWithLetter");
return function(items, letter) {
console.log("Inside Filter: Starts with " + letter);
var filtered = [];
for (var i = 0; i < items.length; i++) {
var itemName = items[i].Name;
if (itemName.startsWith(letter)) {
filtered.push(items[i]);
}
}
return filtered;
};
});

Angular print service timeout issue for multiple print

var userServicePromise = UserService.printBarCodes(sampleId);
userServicePromise.then(function(response) {
if (response != null && response.data != null && response.data.result != null) {
response.data.result.forEach(function(entry) { //three values in the array, iteraring three times.
$timeout(function() {
vm.barCodeImage = angular.copy(entry);
$timeout(function() {
PrintService.printElement("printThisElement"); // display one value three times
}, 1);
}, 2);
});
} else {
toaster.error(response.data.message);
}
});
using print service to print the div, values of the div are populated using the variable(vm.barCodeImage).
But here one value is displaying all the time in the print. tried adding time out interval after the for each, but no luck.
//print service code
(function() {
'use strict';
angular.module('app.services')
.factory('PrintService', PrintService);
PrintService.$inject = [];
function PrintService() {
var service = {
printElement: printElement
};
return service;
function printElement(elem) {
var printSection = document.getElementById('printSection');
// if there is no printing section, create one
if (!printSection) {
printSection = document.createElement('div');
printSection.id = 'printSection';
document.body.appendChild(printSection);
}
var elemToPrint = document.getElementById(elem);
// clones the element you want to print
var domClone = elemToPrint.cloneNode(true);
printSection.innerHTML = '';
printSection.appendChild(domClone);
window.print();
window.onafterprint = function() {
printSection.innerHTML = '';
}
};
}
})();
The expected result for this should be three different print(suppose loop size is 3, it should be 7858,7859,7860), but here it displays all same.
printThisElement id is an HTML.
<div id="printThisElement" class="onlyprint" >
<table>
<tr>
<td>{{ ctrl.instCode }}</td>
<td align="center">{{ ctrl.date | dateDisplayFilter}} </td>
</tr>
<tr>
<td colspan="2" align="center"> <img ng-src="data:image/JPEG;base64,{{ctrl.barCodeImage}}"> </td>
</tr>
<tr>
<td colspan="2" align="center">{{ ctrl.user.name }} </td>
</tr>
<tr>
<td >Reg Id: {{ ctrl.regIdLookup }}</td>
<td align="center">{{ ctrl.testName }}</td>
</tr>
</table>
</div>
Ok, I supposed your binding is wrong. printThisElement refer to single data in controller. So if you have multiple entries, it must be an array.
I suggest to you to use a directive instead of a service to print element in DOM.
I create a little plunker to illustrate it : https://plnkr.co/edit/QvmqV88wZCYbsehMWh3W?p=preview
This plunker show how from an array resulting of calling an async service you can display all entries.
The directive is very simple :
.directive('print', function() {
return {
restrict: 'E',
scope: {
data: '='
},
template: '<div id="printThisElement" class="onlyprint" ><table><tr> <td>{{ data.instCode }}</td></tr><tr><td>... Other values in data ...</td></tr></table></div>',
}
})
The template of the directive is your printThisElement id. With this way you can display multiple result isolate by directive.
Hope this will help you
Edit : Solution for the problem was report on this stack Inconsistent Data on multiple page printing on a printer

watching ng-repeat objects used outside of of ng-repeat

Ok I have created a ng-repeat to get all users created by an $http.get. This get request updates every 5 secs by using $interval and displays individual user data when clicked by calling $scope.goInfo(data). This $scope.goInfo(data) is used throughout the page to show user data, but is created by the ng-repeat (but not always used in ng-repeat). How can I have this data obj created by ng-repeat update every 5 secs outside of ng-repeat? I can't wrap $scope.goInfo() in a $interval.
EXAMPLE
//CONTROLLER//
function liveFeed(){
$http.get('some URL').then(function (user) {
$scope.user = user.data;
console.log('user data is', $scope.user);
});
}
//Updates get req every five secs//
$interval(liveFeed, 5000);
//gets data obj from ng-repeat, needs to be updated every 5 secs.//
$scope.goInfo = function (data) {
$scope.name = data.name;
$scope.beats = data.beats;
}
HTML
<table>
<th>First Name: John</th>
<th>Last Name:</th>
<tr ng-repeat="data in user" ng-click = "goInfo(data)">
<td>{{data.name}}<td>
</tr>
</table>
<span>{{beats}}</span><!--needs to update every 5 secs, outside of ng-repeat and be binded to the user that was clicked on-->
You need to reset selected object after you retrieve new data. Basically, you just need to find corresponding records in new array of objects and set it as selected again.
Something like this should do the trick:
function liveFeed() {
$http.get('some URL').then(function(user) {
$scope.user = user.data;
// Find the record that was selected before this update
if ($scope.selectedUser) {
$scope.selectedUser = $scope.user.filter(function(obj) {
return obj.name === $scope.selectedUser.name; // or compare by unique id
})[0];
}
});
}
// Updates get req every five secs
$interval(liveFeed, 5000);
// Gets data obj from ng-repeat, needs to be updated every 5 secs
$scope.goInfo = function(data) {
$scope.selectedUser = data;
}
and HTML will use selectedUser:
<table>
<tr>
<th>First Name: John</th>
<th>Beats:</th>
</tr>
<tr ng-repeat="data in user" ng-click="goInfo(data)">
<td>{{data.name}}<td>
<td>{{data.beats}}</td>
</tr>
</table>
<span>{{selectedUser.beats}}</span>

Extending ngRepeat array without digest the whole array

When you have an expandable array, what would be the most sufficient way to extend array, without digesting the whole array over.
[].push.apply(scope.table, extending);
.filter('to_trusted', ['$sce', function ($sce) {
return function (text) {
return $sce.trustAsHtml(text);
};
}])
<tbody>
<tr ng-repeat="row in table track by row.index"
once-class="row.theme"
ng-bind-html="table[row.index].tpl | to_trusted">
</tr>
</tbody>

Multiple ng-repeat on single element

Is this possible to achieve a code like this:-
<tr ng-repeat="data in dataArray,value in valueArray">
{{data}} {{value}}
</tr>
I am having two arrays I want to show them in single row.
PS: I am not asking for syntax. I am looking for logic to achieve this
Thanks
Like :- "http://jsfiddle.net/6ob5bkcx/1/"
You should be doing this in the controller, not in the view. Map the dataValues into a key/value pair object and reference the values array using an index. This assumes that each data key has a corresponding value key.
Controller:
var dataArray = [];
var valueArray = [];
this.repeatData = dataArray.map(function(value, index) {
return {
data: value,
value: valueArray[index]
}
});
View:
<tr ng-repeat="data in repeatData">
{{data.data}} {{data.value}}
</tr>
Does this suits your need
http://jsfiddle.net/jmo65wyn/
Your data, value array as object array
this.obj = [{data: 'a', value :true}, {data: 'b', value:true}];
And you loop like this
<div ng:repeat="o in obj">
{{o.data}} and {{o.value}}
<input type="checkbox" ng:model="o.value">
</div>
Angular ng-repeat does not support it but still you can write your own custom directive according to your requirements.
Update Section
var traverseCollection = angular.module("CollectionTraverse", []);
traverseCollection.directive("repeatCollection", function(){
return {
restrict: "A",
scope: {
model: "="
},
controller: controller: function($scope) {
var collectionList = $scope.model;
angular.forEach(collectionList, function(obj, index) {
angular.forEach(obj, function(data, index) {
});
});
}
}
});
Your scope should contains the list of your collection objects : $scope.collectionList = [dataArray, valueArray];
Usage in HTML:
-------------------------------------------
<div repeat_collection model="collectionList"></div>
This directive will be generic to traverse list of collections and yes in the above code there can be some syntactical errors because i did not run it. Its your luck.
If you have, for any reason, two arrays with the same length and where their contents are corresponding (array1[0] correspond to array2[0], ..., array1[n] correspond to array2[n]), you can use AngularJS's track by (which was introduced for the 1st time in the version 1.1.4) like this for example :
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.1.4/angular.min.js"></script>
<table ng-app="" ng-init="names=['Bill','Billa','Billy']; ages=['10', '20', '30']">
<tr ng-repeat="name in names track by $index">
<td>{{ name }} is {{ ages[$index] }} years old.</td>
</tr>
</table>
Hope that can help.
if you want something like a list with two or more items in the same row:
in html file:
<li ng-repeat="item in items">
<i class="material-icons">{{navItem[1]}}</i>{{navItem[0]}}</li>
in js file:
$scope.items = [
["Home", "home"],
["Favorite", "favorite"]
]

Resources