IndexedDB callback not updating UI in angularjs - angularjs

I am using the following library to access IndexedDB in Angularjs on a new Chrome App: https://github.com/aaronpowell/db.js
When I try to update the UI on App startup by using this :
db.orders.query().all().execute().done(function(results) {
$scope.ordercount = results.length;
});
in my main.html I have used the ordercount variable as:
Orders : {{ordercount}}
However, the UI is not updating unless I do ng-click or any other ng-* events. All I need is to show number of orders when my app is loaded. I tried $scope.apply(), but it throws error saying apply() is not available.
Please help.

Since you are getting the values from out side of the angular js you need to do it like this,
$scope.$apply(function(){
$scope.ordercount = results.length;
})

It seems like you access $scope from out side of the angular world. You should get scope object first if you want to notify angular that the data had been updated.
//assume you have a controller named "dbCtrl" e.g., <div id="container" ng-controller="dbCtrl"></div>
angular.element($("#container")).scope().$apply(function(){
$scope.ordercount = result.length;
});
Hope this is helpful.

Related

Running a method in angular using ng-init

I am fairly new to angular, I am making an app which has in app purchases. The current method I have for loading in the products is being called through using ng-click. What I want is for this method to be called when the page loads so I have tried using ng-init but unfortunately this doesn't work.
Below is the links to the code I have tried and used:
https://gyazo.com/645e9a0554aab8d11f6d96b2b159a833
https://gyazo.com/68d305ab5ffdbf94db4cda5539313947
Thanks in advance
Ionic will automatically load anything inside the controller when a user goes to that page.
.controller('LoadItemsCtrl', function($scope) {
loadItems();
function loadItems(){
//Code Here
}
})

How to wait for Meteor subscription before launching angular app

I am using angular-meteor with pascalprecht.translate
the translations object have to be stored in the database in order that some users can modify the translations via a back-office
I subscribe the collection containing the translations and loads them in the .config()
it works well BUT when loading the application the page is rendered before the subscription is ready.an during a short period of time the texts are not translated.
I have to do something in order that we always see translations even during the begining
My question is the following:
Is it possible to make angular wait for the subscription to be ready before it is launched ?
Best regards
bboisvert
angular.module('test').config(['$translateProvider', function ($translateProvider) {
Meteor.subscribe('settings', function(){
test = Settings.findOne({name: "translations"});
$translateProvider.translations('fr-FR', test['fr-FR']);
$translateProvider.translations('en-EN', test['en-EN']);
});
}]);
In the Meteor.subscribe callback, you could do $rootScope.$broadcast('meteorSubscribed')
on your root-level directive/controller listen for it and set a $scope variable to say it is loaded. You could then use that variable for ng-if or ng-show
example:
$scope.$on('meteorSubscribed', function(){
$scope.meteorReady = true;
});
in template:
<div ng-app="test" ng-controller="RootController" ng-show="meteorReady">
<!-- your app here -->
</div>
You could also circumvent the whole event + controller setup and just set $rootScope.meteorReady = true; right in the Meteor.subscribe callback. Really depends on the setup of your app.

How to refresh iframe url?

I am creating an app using ionic in which I am displaying a URL using iframe.
This is the HTML code:
<iframe id="myFrame" width="100%" height={{iframeHeight}}>
This is the angular js:
$scope.iframeHeight = window.innerHeight;
document.getElementById("myFrame").src = value['url'];
Everything is working, however when I make changes on the site from the backend and refresh the app the new changes are not appearing in the app.
The thing you are doing in your code is not a valid way of doing it. You are manipulating DOM using native method that will not run digest cycle, you need to run it manually by doing $scope.$apply(). That will solve your problem but generally you should not do DOM manipulation from controller which is considered as BAD practice. Rather I'd suggest you to use angular two way binding feature. Assign url in scope scope variable and add that on iframe tag using ng-src="{{url}}" so that src URL will be updated by angular and as url get updated iframe will load content from src URL in it.
HTML
<iframe id="myFrame" width="100%" ng-src="{{url}}" height={{iframeHeight}}>
Code
$scope.url = "http://example.com"
As you change scope variable in the controller the the src of iframe will also gets change and iframe will reload the content.
Update
To solve caching issue you need to append current date time to you url that will every time make a new URL and it won't be cached by the browser. Something like $scope.url = "http://example.com?dummyVar="+ (new Date()).getTime() by using this it will never harm your current behavior, only you need to append dummyVar with current time value which would be always unique.
$scope.url = "http://example.com?dummyVar="+ (new Date()).getTime()
Refreshing didn't work for me with timestamp as in Pankaj Parkar's answer, so I solved it in a bit of a hacky way, which just toggles ng-if element off and on again, and forces iframe to load.
Template:
<iframe ng-if="!vm.isRefreshing"></iframe>
Controller:
refreshIframe() {
this.isRefreshing = true;
$timeout(() => {
this.isRefreshing = false;
}, 50);
}
As #pankajparkar suggested in his answer, I'd suggest you using angular 2-way data binding.
In addition to that, you need to wrap the urls with $sce.trustAsResourceUrl function in order to your iframe to work.
<iframe id="myFrame" width="100%" ng-src="{{url}}" height={{iframeHeight}}>
And
$scope.url = $sce.trustAsResourceUrl("http://example.com");

using data from a callback from Ebay api in Angularjs

I am trying to use the ebay api in an angular.js app.
The way the api works by itself is to pass data to a callback function and within that function create a template for display.
The problem that I am having is in adding the data returned from the callback to the $scope. I was not able to post a working example as I didnt want to expose my api key, I am hoping that the code posted in the fiddle will be enough to identify the issue.
eBayApp.controller('FindItemCtrl', function ($scope) {
globalFunc = function(root){
$scope.items = root.findItemsByKeywordsResponse[0].searchResult[0].item || [];
console.log($scope.items); //this shows the data
}
console.log($scope.items); //this is undefined
})
http://jsfiddle.net/L7fnozuo/
The reason the second instance of $scope.items is undefined, is because it is run before the callback function happens.
The chances are that $scope.items isn't updating in the view either, because Angular doesn't know that it needs to trigger a scope digest.
When you use the Angular provided async APIs ($http, $timeout etc) they have all been written in such a way that they will let Angular know when it needs to update it's views.
In this case, you have a couple of options:
Use the inbuilt $http.jsonp method.
Trigger the digest manually.
Option number 1 is the more sensible approach, but is not always possible if the request is made from someone else's library.
Here's an update to the fiddle which uses $http.jsonp. It should work (but at the moment it's resulting in an error message about your API key).
The key change here is that the request is being made from within Angular using an Angular API rather than from a script tag which Angular knows nothing about.
$http.jsonp(URL)
.success($scope.success)
.error($scope.error);
Option 2 requires you to add the following line to your JSONP callback function:
globalFunc = function(root){
$scope.items = root.findItemsByKeywordsResponse[0].searchResult[0].item || [];
console.log($scope.items); //this shows the data
$scope.$apply(); // <--
}
This method tells Angular that it needs to update it's views because data might have changed. There's a decent Sitepoint article on understanding this mechanism, if you are interested.

Angularjs view not reflecting the data retrieved from pouchDB (in browser database)

Background:
I am building my offline application which uses AngularJS for UI and PocuhDB for locally storing the data retrieved from the server.
Issue:
The data retrieved from PouchDB is not getting rendered in the UI.
Controller:
$scope.retrieveView = function (sys, code, majorVer, minorVer) {
var promise;
promise = dataService.getDataFromLocalDb().then(
function(dataFromPouchDb){
$scope.data = dataFromPouchDb.data;
});
return promise;
}
And then in the UI code I have the following :
<h1> {{data}}</h1>
I have debugged the code and everything seem to work fine. But the data is not getting displayed in the UI.
If I hard code a value to the data field then its getting rendered in the UI
$scope.data ="TEST";
This question is kind a old but I just came around it.
Issue is that Angularjs is based on so called digest cycles. When your model or view is changed digest cycle is triggered, watch for changes and update model or view respectively. It is so called two way data binding.
This digest cycle is not triggered periodically on some time base but on events instead. Those events are angular directives like ng-click, ajax calls $http or some other angular events like $timeout. You can find more information about digest here.
In general you should use those things when working with angular application to avoid such situations. In some cases its not possible however like in your case when getting data from DB. Digest cycle is not triggered and your view is not updated by angular.
Workaround for this is manually trigger $digest cycle. Way you have described:
if(!$scope.$$phase) {
$scope.$digest();
}
is working but considered as angular anti-patern and is discouraged by angular team, you should use:
$timeout();
instead. For more information see this answer.
I would maybe consider adding $timeout() call to hook for insert, update, delete hooks or events. Maybe pouchDB sync could be helpfull there.
The code you show seemed correct, maybe you can use console.log() to track the progress of the data. I think the problem might not in this layer. Maybe in the area where you wrapped getDataFromLocalDb(), track and find if the data have transfer to here, or where it disappeared.
The code started to work when i added the following :
if(!$scope.$$phase) {
$scope.$digest();
}
But i have no idea what magic does this code do.
It would be a great help if some some could advice.
The complete code that works now is :
$scope.retrieveView = function (sys, code, majorVer, minorVer) {
var promise;
promise = dataService.getDataFromLocalDb().then(
function(dataFromPouchDb){
$scope.data = dataFromPouchDb.data;
if(!$scope.$$phase) {
$scope.$digest();
}
});
return promise;
}

Resources