I'm writing a function which will iterate through an array with some time interval.
eg:arr=[1,2,3,4,5,6,7]
And I want to show each element with angular interval.
$interval(step,5000,7);
function step(i){
console.log(arr[i]);
}
So it'll output the numbers inside the array in a 5 seconds' interval. How can I pass the parameter into the function? Thanks.
You could also do this way:
var arrOrig =[1,2,3,4,5,6,7],
arr = angular.copy(arrOrig), //if you want it for later
cancelPromise = $interval(step, 5000);
function step() {
console.log(arr.shift()); //take out the item from top of array
if (!arr.length) { //once array runs out
$interval.cancel(cancelPromise); //cancel interval
}
}
var arr = [1, 2, 3, 4, 5, 6, 7];
var $interval = angular.injector(['ng']).get('$interval');
var cancelPromise = $interval(step, 5000);
function step() {
console.log(arr.shift());
if (!arr.length) {
$interval.cancel(cancelPromise);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
arr.forEach(function (number, idx) {
$timeout(function () {
console.log(number);
}, 5000 * (idx + 1));
});
You want to use $timeout rather than $interval because calling $interval will set up an interval each time for each number and it won't stop until it's cleared explicitly.
var i=0;
$interval(function(){
step(i);
i++
},5000);
function step(i){
console.log(arr[i]);
}
This code will display the numbers one at a time, on repeat:
var getNextNumber = (function(){
var i = 0;
var numbers = [1,2,3,4,5,6,7];
return function(){
if(i >= numbers.length){
i = 0;
}
return numbers[i++];
};
})();
$interval(function(){
var number = getNextNumber();
console.log(number);
},5000);
See this working jsfiddle.
If you want to display them only once, use one of the $timeout solutions from one of the other answers. $interval is all about repeating some command for an indefinite amount of time, whereas $timeout is more about performing a command once in the future. See this answer for more.
Related
I do have a print Service developed using angular js,
Is there any efficient way that I can mention the no.of times.
Currently I can loop through this code and call n number of times
PrintService.printElement("printThisElement");
Print service code
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(elemToPrint);
$timeout(function(){
window.print();
}, 0);
window.onafterprint = function() {
printSection.innerHTML = '';
}
};
Can I loop thru this ?
$timeout(function(){
window.print();
}, 0);
Not sure of your question but from what I understand, your PrintService can be called from various controllers within your app. And you want to control the number of times this method can be called.
You can use a global variable, and check its value inside the PrintService.printElement("printThisElement"); method. If the value exceeds your limit, return an error.
var myApp = angular.module('myApp', []);
myApp.value('test', 0);
myApp.factory('PrintService ', ['test', function (test) {
this.printElement = function () {
//check 'test' value and then run print code
//test++ if printing
}
}]);
$timeout does not loops the function, $timeout used to execute the code inside it only once after a time out.
Instead use a variable to loop using if condition.
HEre is an example:
var count = 0;
function myFunction() {
count++;
if(count > 5)
{
return; // you can either return or execute any other code.
}
else
{
window.print();
}
}
Hi i'm building a form doing a lot of calculations, such as summarizing keys in objects
[
{ bar: 5, .. },
{ bar: 6, .. },
...
]
I use this expression in currently 35 places in my HTML. Sometimes connected to further calculations and with different keys
<div>
{{ sumKeys('bar') + foobar }}
</div>
The function i use is declared as
app.controller('someCtrl', function($scope){
$scope.sumKeys= function(key){
return (calculated sum);
}
}
My problem is, that if i write a single letter into any input field the sum function is called about 400 times. I know there is a rule, that calls the function if a scope is changed up to 10 times, but isn't there a more efficient way?
Can i output the result without changing the scope? Or force this calculation just to be done once? I know the results do not change any involved scope. So the results should be the same after 2 iterations.
I also implemented the function as a filter with same results.
What you're looking for is a SINGLETON service. You can make one in angular like this: (one of my real examples)
angular.module('ocFileUpload', [])
.service('ocFileUpload', ['$http', '$rootScope', function ($http, $rootScope) {
// Will house our files
this.files = [];
// This fn appends files to our array
this.addFile = function(files){
for (var i = 0; i < files.length; i++){
this.files.push(files[i]);
}
};
this.getFileDetails = function(ele){
// push files into an array.
for (var i = 0; i < ele.files.length; i++) {
this.files.push(ele.files[i])
}
};
this.removeFile = function(fileToRemove){
var indexOfFile = this.files.indexOf(fileToRemove);
this.files.splice(indexOfFile, 1);
};
this.clearFiles = function(){
this.files = [];
};
// Return files array
this.getFiles = function(){
return this.files;
};
}]);
Then just simply use it in your controller/directive:
.controller(['ocFileUpload', function(ocFileUpload){
var ref = ocFileUpload.getFiles();
}]
I am looking to use a playsound function in midi.js to loop an array, with chords that i select, maybe 4 diff ones. But i can't figure it out. I can get it to do a single array, but not multiple, and it does not loop, only plays the amount of time I set it to (now 8).
window.onload = function () {
MIDI.loadPlugin({
soundfontUrl: "../MIDI.js/examples/soundfont/",
instrument: "acoustic_grand_piano",
onprogress: function(state, progress) {
console.log(state, progress);
},
onsuccess: function () {
for (var i = 0; i < 9; i++){
playsound([37,59,61,71,80])}
}});
var delay =1;
function playsound($chords)
{
var velocity = 127;
MIDI.setVolume(0, 127);
MIDI.chordOn(0, $chords, velocity, delay);
MIDI.chordOff(0, $chords, delay+1);
delay += 1;
}
Your code should work, except that for the timing to work predictably, I found you have to wait a bit after the success callback is called. If you call right after load, notes are played irregularly and out of sequence.
I recommend using a function like playChords below and testing well after load by calling the function with a button press. For example, this function plays three different chords at 1/2 second intervals, a total of 9 times.
chords = [[37,59,61,71,80],[38,60,62,72,81],[39,61,63,73,82]];
function playChords() {
for (var i = 0; i < 9; i++){
playChord(i/2, chords[i%chords.length]);
}
}
function playChord(delay, chord) {
MIDI.chordOn(0, chord, 127, delay);
MIDI.chordOff(0, chord, delay+1);
}
I have a string which is in "1200:2,1300:3,1400:2" format. I need this to be printed like
<p>1200</p><p>2</p>
<p>1300</p><p>3</p>
<p>1400</p><p>2</p>
I tried using filter,
return function (input) {
//Validate the input
if (!input) {
return '';
}
var hoaArray = [];
var inputArray = input.split(',');
for (var i = 0; i < inputArray.length; i++) {
var adminTimeArray = inputArray[i].split(':');
hoaArray.push({ 'adminTime': adminTimeArray[0], 'dose': adminTimeArray[1]?adminTimeArray[1]:'' });
}
return hoaArray;
};
and inside html like
<p ng-repeat="timing in timing_list | formatter">{{timing.}}</p>{{timing .adminTime}}</div>
I am getting the following error,
Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
Watchers fired in the last 5 iterations: [[{"msg":"fn: regularInterceptedExpression","newVal":36,"oldVal":34}],[{"msg":"fn: regularInterceptedExpression","newVal":38,"oldVal":36}],[{"msg":"fn: regularInterceptedExpression","newVal":40,"oldVal":38}],[{"msg":"fn: regularInterceptedExpression","newVal":42,"oldVal":40}],[{"msg":"fn: regularInterceptedExpression","newVal":44,"oldVal":42}]]
Could anyone please help me understand what am I doing wrong?
Regards,
Raaj
In the IndexController.js file:
var inputString = "1200:2,1330:3,1400:4,1500:3";
var formatInputString = function (input) {
//Validate the input
if (!input) {
return '';
}
var hoaArray = [];
var inputArray = input.split(',');
for (var i = 0; i < inputArray.length; i++) {
var adminTimeArray = inputArray[i].split(':');
hoaArray.push({ 'adminTime': adminTimeArray[0], 'dose': adminTimeArray[1] ? adminTimeArray[1] : '' });
}
return hoaArray;
};
$scope.inputString = inputString;
$scope.formattedString = formatInputString(inputString);
In the HTML file:
<div ng-repeat="timing in formattedString" >
{{timing.adminTime}}
{{timing.dose}}
</div>
The issue here - possibly a limitation or a bug in Angular - is that your filter creates new array objects every time it runs. ng-repeat uses under the covers $scope.$watchCollection to watch for the expression "timing_list | formatter" - this watcher always trips up because, in trying to detect a change in a values in the collection, it compares objects with a simple "!==" - and the objects are always new and different objects.
In short, this is another way to reproduce:
$scope.items = [1, 2, 3];
$scope.$watchCollection("items | foo", function(){
});
where foo is a filter that operates on each element in the array creating a new object:
.filter("foo", function(){
return function(inputArray){
return inputArray.map(function(item){
return {a: item};
});
};
});
So, to answer your question - you cannot with Angular v1.3.15 use a filter that returns an array with objects (without some funky object caching) with $watchCollection, and by extension, with ng-repeat.
The best way is to create the array first (with ng-init or in the controller), and then use it in the ng-repeat.
I am $watching the $scope.randomObjects in my directive. The $watch will throw an error if the function is not stable and I think that my curried function inside getDesiredAmountOfObjects is idempotent. Is here something going on with ngResource -objects that I can not see?
How can I fix this? Also the desiredAmount is fixed for now.
Here is snippet from my controller:
..
var getDesiredAmountOfObjects = function (objects, randomObjects) {
return function (desiredAmount) {
var amount = desiredAmount || 1;
if (amount >= objects.length) {
return objects;
}
var randoms = randomObjects.slice(0, amount);
//logged objects are always the same in each $digest loop.
//including the $$hashKey
console.log(random);
return randoms;
};
};
//this will initialized only once in controller
ObjectRes.query(function(data) {
$scope.objects = data;
var randomObjects = [];
angular.extend(randomObjects, data);
randomObjects.sort(function () {
return 0.5 - Math.random();
});
$scope.randomObjects = getDesiredAmountOfObjects($scope.objects, randomObjects);
});
..
I can't see everything because I haven't seen how the $watch and views are set up, but something jumps out at me.
If randomObjects is being called from within a watcher, and set to a value on the scope which is also watched, it will cause an infinite $digest cycle.
This is because you are constantly returning a new array reference (slice returns a new array). The watcher of the result will recognize that the reference changed, which will require a new loop of the digest, which will ask for new randomObjects which will trigger that something changed, etc.
Usually, you fix this by making sure your function returns references to the same object, and does not create new arrays. In your case, you are calling slice which creates a new array every time. You need to make sure this function returns the same array every time.
Something like this, perhaps?
var getDesiredAmountOfObjects = function (objects, randomObjects) {
var result = [];
return function (desiredAmount) {
var amount = desiredAmount || 1;
if (amount >= objects.length) {
return objects;
}
// clear the result array and put randoms into it
result.length = 0;
result.push.apply(result, randomObjects.slice(0, amount));
//logged objects are always the same in each $digest loop.
//including the $$hashKey
console.log(result);
return result;
};
};