After executing get or put in indexeddb, the callback is updating the scope.
The problem is, no update is being triggered in the ui!
A common solution is to use apply or digest but that is wrong, you should NOT use those operations. Angular should update it automatically.
Now my guess, after reading some stuff, is that the callback is being executed in a different context, outside of the scope.
My question is basically: how can I execute an indexeddb callback in an angularjs scope context?
EDIT:
A rough look on how its built:
GetObjectStoreData(iDb, objectStore, function (res) {
$scope.result = res;
}
The call is made from inside the scope so the scope is used in the callback. The callback parameter is the contents of the object store
You asserted that you should not have to use Scope.$apply because AngularJS should do it for you.
This is true only for callbacks managed by Angular. For example, when you use $timeout in place of window.setTimeout, angular wraps your provided callback in a call to Scope.$apply, causing a digest cycle to run once your callback completes. If you interact directly with browser APIs rather than calling through AngularJS, it is your responsibility to call Scope.$apply at the appropriate time.
If you don't want to manage the scope directly, you could instead use a wrapper library like angular-indexedDB, which (amongst other things) handles the scope notifications when callbacks occur.
Related
In Angular 1.x, the digest cycle use to take care of updating view when data is changed on scope. How does property binding and interpolation works in Angular 2 when data is changed in component?
Angular2 has its own version of Zone (called NgZone) that take care of detecting changes. When NgZone detects a change is called an event called onTurnDone. Angular has a component called ApplicationRef that listens for this event to occur and when it does the tick() method (of the ApplicationRef) is called. The tick() method, at this point, is the responsible for the changeDetection cycle that updates the view.
If I've understood the question you have made, then maybe you'd like to read a post that goes deeper into this subject of the change detection strategy:
https://blog.thoughtram.io/angular/2016/02/22/angular-2-change-detection-explained.html
I'm struggling to understand why you'd need to use $emit rather than using the controller as syntax and directly accessing & updating data on the parent scope. What are the use cases?
It's obviously more efficient to call a method on a parent scope directly, rather than using $emit (or $broadcast) to dispatch an event. But there are some valid reasons to do it.
Here's some reasons that come to mind:
You want to emit an event that more than one application component can receive/process.
You want to de-couple your components so that in the future the message may be processed by a different controller (or maybe a service or a directive, etc.).
You want to emit an event that a service/factory can consume (these are not associated with any view/$scope, but you can inject the $rootScope into them).
Our clients add our JS tag to the head of their page. Our tag needs to know when reactJS has finished before it modifies the page.
I have tried using jQuery's $(document).ready() but this fires before reactJS has finished. I can use $(window).load() but if there are a lot of images on the page, this would be too slow.
What are the options to bind to the completion of React.renderComponent?
Set off the execution of your code via the optional callback that you can pass to React.renderComponent. This callback won't execute until React.renderComponent has finished. If you don't have access to the code that is executing React.renderComponent (which I've just realized is almost definitely the case) then there is no definitive/reliable way to listen for the execution of a function unless of course that function exposes some sort of event that you can listen for, or even guarantees that "x" will be the case once it has finished. Sadly for your case, this doesn't appear to be an option with React.renderComponent.. Let me know if you have any further question.
If you don't have direct control over the React code, you could always see if you can sniff for relevant changes via DOM Mutation events.
I have a handful of directives on a page that all share the same data. I have a heavy API call that needs to be made somewhat frequently to update these directives. Each directive contains the data in three states:
A display state showing the results and,
A loading state indicating that the call to the API is being made
An error/empty state
How the state is shown is directive specific and is not always a matter of updating some css or a variable. Sometimes it requires the calling of a function.
Trying to do this it seems I would have to listen for my trigger with a watch, then broadcast that I'm 'in loading' to all my directives. Then broadcast that the resource was loaded to resolve the loading state if it succeeded, else broadcast that there'd been an error. That's a lot of different broadcasts and 'on's in all my directives. Is there a more efficient way invoking direct methods on child directives?
Sometimes i need to use $scope.$apply, for example when i use jQuery ajax or some non-angular-js eventlisteners. In those cases i have an asynchronous callback and there i use $scope.$apply so that changes to the scope are picked up by angular and watches are triggered. Please correct me if that is the wrong use of $scope.$apply.
This seems to work and the view is updated. However in some rather rare cases I get a "digest already in progress" error. I don't see how this can be possible, since the callback is not synchronous. So I wonder if it is possible that my asynchronous callback with the $scope.$apply in it can by chance collide with an ongoing digest? If so, how can I prevent this from happening?
edit:
One possibility to check for a digest is checking $$phase: if (!$scope.$$phase) $scope.$apply() but this is an anti-pattern as the angularjs wiki says: https://github.com/angular/angular.js/wiki/Anti-Patterns
I want to fully understand why it is possible that I encounter a digest in an asynchronous callback. And why this is an antipattern.
I recently asked a similiar question on why if (!$scope.$$phase) $scope.$apply() is an anti-pattern here: Why is using if(!$scope.$$phase) $scope.$apply() an anti-pattern?
The answer there also contains the answer to this question.
You are calling $apply on an existing scope, so it's definitely possible that you are calling apply while it is currently digesting. Some people might suggest checking $$phase but that has been discouraged as an anti-pattern
You have two options if you are running into this problem, even occasionally. One is to do as the anti-pattern implies and make sure your $scope.$apply is as high as possible up the chain.
However, this won't help if you are asynchronously calling $apply on the same $scope in rapid succession. The answer then is often to throttle the $apply so that it only happens every few hundred milliseconds. This is a common practice when using something like socket.io that can fire events which could cause you to re-apply many times.
I think, that its normal, but it will be better to move code to services and resources with angular style. To prevent error you can check current state
scope.$$phase
To prevent calling $apply
Async Callbacks are an appropriate time to use the $apply, there are edgecases I have run into as well where i get that error. They are usually because I am doing something wonky, I have found that a "Conditional Apply" works well for these.
if(!$scope.$$phase) {
//$digest or $apply
}
AngularJS : Prevent error $digest already in progress when calling $scope.$apply()