How does AngularJS implements the 2-way data binding? The view to model update is understandable i.e. it can be achieved through the JS listeners but I wanted to understand the model to view update? As at the core angular models are js variables, so how does the Angular listen to the change in js vars?
I know that each model has a watch which compare the new value with the old one but what triggers this check(the js implementation)?
Does it uses Javascripts watchers or a time interval for checking?
Angular defines a concept of a so called digest cycle. This cycle can
be considered as a loop, during which Angular checks if there are any
changes to all the variables watched by all the $scopes. So if you
have $scope.myVar defined in your controller and this variable was
marked for being watched, then you are explicitly telling Angular to
monitor the changes on myVar in each iteration of the loop.
Basically AngularJS binds event handlers to any element that interacts with Angular ($scope, directive, ...), every time the event fires, $apply is called which internally calls $digest which will trigger the re-evaluation of all the $watches.
AngularJS made a smart assumption that model changes happen only on user interaction / events:
DOM events
XHR responses firing callbacks
Browser's location changes
Timers (setTimout, setInterval) firing the callbacks
Or trigger on certain events
Input directives+ngModel, ngClick, ngMouseOver etc.
$http and $resource
$location
$timeout
When one of these 'assumptions' is triggered, the digest cycle is kicked off:
To quote Pawel Kozlowski, Mastering Web Application Development with AngularJS:
AngularJS does not use any kind of polling mechanism to periodically
check for model changes
More detailed insights
Have a look at https://www.youtube.com/watch?v=SYuc1oSjhgY for a really deep dive into the digest cycle.
Related
This is a general question about AngularJS.
AngularJS does not raise an event to notify when the digest cycle has ended. AngularJS suggests using $timeout as a solution to queue your work to be run after the current digest cycle (also waits for DOM rendering to be completed by the browser).
Does anyone know how to know if $scope.$apply() and $scope.$digest() have ended without using $timeout?
You can use $scope.$digest(), before your business logic function or $scope.$apply(function(){/*your business*/}) but this method like timeout function.
Is it possible to compile AngularJS application to remove ng-* directives like (ng-click) and generate plain HTML like Angular 2+? If we inspect Angular 2 application with say chrome dev tools, it does not show event handlers like onClick. However AngularJS shows ng-click, ng-for etc.
Short answer:
No.
Long answer:
I won't prvide one, as your question touches many (complex) topics that are already explained elsewhere and possibliy better than I could do, but I will provide some usefull links in my short explanation.
Medium answer:
What you asking for is not possible, because AngularJS uses a different approach for change detection and event bindings.
One of the cool things about AngularJS/Angular is it's ability to to detect changes and perform updates automtically. To make this possible, Angular(JS) has to notice if things change.
Taking your example with the click event, AngularJS uses event based directives to notice the click event, whereas Angular performs a event binding using one-way bindng from the template view to the component. Angular has this possibility because it uses Zones to get aware of changes. Therefore it doesn't need a directive as AngularJS did.
This explains why you don't see event handlers on the HTML element, because Angular directly sets up the event binding. You can verify that the event is handled by Zone.js if you check the Event Listeners tab in Chrome:
Other usefull links to the topic:
https://angular.io/guide/architecture-components#data-binding
https://blog.thoughtram.io/angular/2016/01/22/understanding-zones.html
When I was testing the order of events in ui-router, I was expecting that $stateChangeSuccess would be after $viewContentLoaded but it was not, as shown in the screenshot below:
If I am loading the views remotely, via templateUrl property, it may take sometime for it to load (depending on the network connection). I was showing my loading indicator by watching stateChangeSuccess/Error event and I don't want the loading indicator to stop prematurely when the view is not loaded yet. I guess I would watch $viewContentLoaded event but I want to be consistent with my watches (stateChangeStart/Success) etc. I am wondering if stateChangeSuccess actually waits until after view content loads?
It always loads in that order.
I just tested it by putting a delay in a resolve and in templateProvider (to delay view) and in both cases order of events were same.
Also, when I delayed the view load in templateProvider, $stateChangeSuccess did not fire until the view is loaded (there was nothing in resolves to delay it). So, $stateChangeSuccess does not fire before the view is loaded.
When Angular is bootstrapping or intially digesting forms that are loaded are temporarily $valid even though they have no values, which causes some charts I have to blink whenever those views are loaded. How/Where would you debounce this, or $watch for initial loading to be complete?
I'm currently using AngularJS on a project of mine and I am unsure of when/if I need to manually unbind listeners to the $scope (or scope when in the linking function of a directive for example).
From the documentation, which isn't the clearest, I would guess that you do NOT have to unbind to any listeners on the current scope, but I'm not sure whether or not you would have to unbind to listeners on say, the $rootScope for example.
Any clarification about the lifecycle of components such as a directive or a directive's controller would be appreciated.
Thanks
Angular handles that for you.
When scope is destroyed (for example when new view is loaded via ng-view directive old view's scope is destroyed ) all it's child scopes are destroyed and theirs $watchers and listeners registered via $on as well.
$rootScope isn't destroyed at all during lifetime of your application, so you have to manages it's listeners manually, but generally you register there stuff which should be permanent.
When you register listeners via addEventListener you have to remove them manually as it's not managed via angular.