Angular: Calling function that changes scope variable on interval - angularjs

I've built a function that does some text transformations on a string. I'm calling this function from my view.
I would now like to call this function from a controller with a set interval,every 3 seconds.
I was trying with this in my controller:
$scope.MyTextFunction = function(input) {
cancelRefresh = $timeout(function myFunction(input) {
console.log(input);
// Do things here
cancelRefresh = $timeout(myFunction, 3000);
},3000);
};
I'm having some trouble getting this to work. Specifically, it seems all the functions that are called in the view are being triggered again. So console.log(input) gets called 4 times, then 8 times, then 16 times, etc, every 3 seconds. (I'm guessing this is due to the digest cycle? I'm not totally clear on this).
As you can expect, after staying on this view for 20 seconds the browser becomes unresponsive.
How can I make write a function that
triggers every 3 seconds,
is tied to the scope so I can use the output in the view and
doesn't trigger all the existing functions that already exist in the view?
I've set up a plunkr that contains the text transformation string: http://plnkr.co/edit/JlEBlCBG3roCqkiKegI6?p=preview

Related

AngularJS: Nested http call doesn't update the view

In a particular scenario, I need to call the the github api to retrieve a specific user's info. Then issue a second call to retrieve the user's repositories:
search(login: string): void {
this.user = undefined;
// first call
this.githubApi.getUser(login)
.then(user => {
this.user = user;
// second call
this.githubApi.getRepos(user.repos_url)
.then(reposResponse => {
this.repos = reposResponse.repos;
// I don't like to call this.$scope.$apply() !!;
});
});
}
The first call gets executed and the bound elements to this.user gets updated with no problem in the view.
The second call gets executed and the result is returned successfully and this.repos is set correctly. But, the bound elements on the view are not updated.
If I call this.$scope.$apply() in the very last line of the second callback, it makes the view update work but I guess this is not correct approach.
Any solution?
Well, if you are not willing to use $scope.apply();, try updating your getRepos service response code with:
setTimeout(
() => {
this.repos = reposResponse.repos;
}, 0
)
First you need to know , why Angular-Js is not updating the view.
You have used $scope.$apply(), so I'm assuming you already know , how it works and why we use it. Now , to the problem!
Sometimes when you make a callback - nested callback in particular - Angular does not update the view. Sometimes angular thinks that it does not need to update the view because of callbacks. And the watchers do not take action when the value changes of the variable that they are watching.
Then you use $scope.$apply() to run the digest cycle again (assuming you already know the digest cycle if you don't then let me know). And it makes the watchers to update the view.In your case, digest cycle is not running, that is why angular is not updating the view. If your digest cycle was running , angular would have given you error. So, it will tell angular to run digest cycle again because two-way binding is not working properly.
I don't think there is another way. But if there is a way, I would love to know that way. Also its not a bad approach. It was made for these kind of problems.

Autosave form fields for every 15 sec in AgularJS without using $watch

I want to save a form field values every 15 sec with out using $watch and also it should stop executing once it has been moved to a different form. In the form I will be having many fields so I think $ watch will be having performance issue and also am not sure how to call all fields at once for %watch. So I decided to use $interval but I want to stop this execution once I moved to different controller or different form. If user comes back again to this form again this interval function should start automatically. please would you suggest me best way to handle this.
Use $interval like you are planning to do but assign it to a variable
with $scope.on('$destroy', function() { }); callback you can destroy the interval when switching to a different controller.
var intervalPromise = $interval(function() { // your code }, 15000);
$scope.$on('$destroy',function(){
if(intervalPromise)
$interval.cancel(intervalPromise);
});

ng-repeat too many iterations

I am using angular-meteor and would like to perform a function on each object. I tried running this function within an ng-repeat in the view, but I am getting massive amounts of function calls and can't figure out why. I tried to make it as simple as possible to demonstrate what is going on.
constructor($scope, $reactive) {
'ngInject';
$reactive(this).attach($scope);
this.loaderCount = 0;
this.helpers({
loaders() {
return Loaders.find( {isloader:true}, {sort: { name : 1 } })
}
});
That gives me 26 Loaders. My function just adds 1 to the count every time the function is called:
displayLoaderCount()
{
return ++this.loaderCount;
}
Now in my view, I am looping through each loader, and calling the function. This should in my mind give me 26, but instead I am getting 3836.
<tr ng-repeat="loader in loaderExhaustion.loaders">
<td>{{loaderExhaustion.displayLoaderCount()}}</td>
Can anyone help explain this to me? Ideally I would like to loop over the contents in my module but as the collection is async, when the loop starts the length of the collection is 0, hence why I made the call in the view.
THANKS!
Every time angular enters a change detection cycle, it evaluates loaderExhaustion.displayLoaderCount(), to know if the result of this expression has changed, and update the DOM if it has. This function changes the state of the controller (since it increments this.loaderCount), which thus triggers an additional change detection loop, which reevaluates the expression, which changes the state of the controller, etc. etc.
You MAY NOT change the state in an expression like that. For a given state, angular should be able to call this function twice, and get the same result twice. Expressions like these must NOT have side effects.
I can't understand what you want to achieve by doing so, so it's hard to tell what you should do instead.

Need explanation on a angular direcive load

I just want to understand why in the following jsFiddle 'here is a lo' is printed three times.
http://jsfiddle.net/wg385a1h/5/
$scope.getLog = function () {
console.log('here is a log');
}
Can someone explain me why ? What should I change to have only one log "here is a log" (that's what I would like this fiddle do). Thanks a lot.
Angular uses digest cycles/iterations to determine when state has changed and needs to update the UI. If it finds any change on one of it's cycles, it keeps rerunning cycles until the data stabilizes itself. If it's done 10 cycles and the data is still changing, you'll see a rather know message: "angularjs 10 iterations reached. aborting".
Therefor, The fact that you are seeing the message displayed 3 times is because you have a simple interface. In fact, you can get up to many more such messages in the log, due to the fact that your directive uses {{getLog()}}. Angular keeps evaluating the expression to see if it changed.
To avoid such problems, under normal circumstances, you should store the value returned by the function you want called only once in the $scope object inside the controller and use that variable (not the function call) in the UI.
So in the controller you'd have $scope.log = getLog() [assuming it returns something, and not just writing to the console] and in the directive use the template {{log}}. This way, you'll get the value only once, per controller instance.
Hope I was clear enough.

Angular: scope variable vs function

What is better in Angular - to bind to a variable or to a function. In particular:
Is there any performance penalty due to digest calls or additional watches that are created for a function?
Are there any recommendations for what scope functions should and shouldn't do?
Example for two options:
<!-- With function -->
<button ng-disabled="noDataFoo()">Add</button>
<!-- With variable -->
<button ng-disabled="noDataFlag">Add</button>
Backing controller:
app.controller('sample', function($scope, $http) {
$scope.noDataFlag = true;
$scope.noDataFoo = function () {
return !$scope.data;
};
$http('/api/getdata').success(function(data) {
$scope.data = data;
$scope.noDataFlag = false;
};
});
I'm not a javascript performance expert or anything, but my naive opinion would be that the variable would out perform the function by MAYBE a couple of nanoseconds because it's a 2 step process.
Also, the example above would be just as easily accomplished using:
<button ng-disabled="!data">Add</button>
I made some tests and counted how many times the function is called under different circumstances. It occurs, the function is called the number of times it has binding, sometimes twice the number and it seems to happen after each external activity, like page reload or button click or AJAX call.
In simple words, if you have <button ng-disabled="noDataFoo()"> and then {{noDataFoo()}} in HTML, the function will be called 4 times at page load, then another 2 or 4 times if some $http service brings data, and another 2 or 4 times if some other button was clicked. From experiments, the number is 2 if noDataFoo doesn't change and 4 if it does change. By the way, the same holds for clicks on another controller.
My conclusion is: it's OK to bind to quick functions. For longer ones it's better to keep number of bindings small. And for even longer ones it's wiser to cache the result and handle "manually" cache updates.

Resources