My angular app has/needs two way data binding.
I fetch data from indexedDB using angular service, which is injected in a controller.
I need the view to be updated after the fetch from db is made.
var app = angular.module("app",["ngRoute"]);
app.config(['$routeProvider',function($routeProvider) {
//removed extra routes for simplicity
$routeProvider.when('/grouped',{
templateUrl: 'template/grouped.html',
}).otherwise({
redirectTo: '/grouped'
});
}]);
The controller in the same file
app.controller("AppController",function ($scope,dexiedb) {
$scope.datais={};
$scope.dataisdata={};
$scope.alldata = {};
var scholar = {};
var _db;
window.initial = 0;
var callback_alldata = function(err,data){
if(!err){
/* If I put apply it works*/
// $scope.$apply(function() {
$scope.alldata = data;
// });
}
console.log('in callback_alldata ',err,data);
};
var init = function() {
console.log('hi in init');
dexiedb.getdata(callback_alldata);
console.log($scope);
};
init();
});
The service that fetches data from db
app.service('dexiedb',function(){
var createdData = {};
var _db = null;
var service = {};
//Initialization code which makes connection
service.init = function(){
_db = new Dexie('puppets');
_db.version(1).stores({
snips: "++id, text",
parent: "++id, title, timeStamp"
});
_db.open().then(function(){
service.createdata();
console.log('service.init then called');
}).catch(function(e){
console.log('error opening',e);
});
};
//The actual place where data is fetched and returned
service.createdata = function(callback){
console.log('createdata');
var alldata = [];
_db.transaction('rw',_db.parent, _db.snips, function(){
_db.parent.each(function(par){
var r = {'parent':par,'snips':[]};
_db.snips.where('URL').equals(par.URL).each(function(snip){
r.snips.push(snip);
});
alldata.push(r);
// console.log(alldata);
}).then(function(){
createdData = alldata;
console.log('createdata',createdData);
return callback(null,createdData);
// return createdData;
});
});
};
//The method which is called in the controller
service.getdata = function(callback){
// console.log(createdData);
if (Object.keys(createdData).length==0) {
console.log('createdData was empty');
return service.createdata(callback);
} else return callback(null,createdData);
}
service.init();
return service;
});
I understand that $scope.apply
should be used if the place where variable is being updated is not in angular scope. While in callback won't the angular scope be present?
The data is fetched and logged in console but it does not show up in the view until I click on another route and then come back again.
My understanding of promises/callback isn't solid yet, is the problem due to mishandling of callbacks?
The issue is that Angular is not aware of the change made to $scope (i.e. $scope.alldata = data;
).
Changes made to the $scope
in your controller will be updated immediately, however your code is inside a callback. Angular reaches the end of the controller before the callback is fired, and so it misses the digest cycle. It cannot know your callback was invoked.
While you are updating the $scope
in the callback, that doesn't trigger a new digest cycle.
dexiedb
does not appear to be using $http
, you will therefore need to use $scope.$apply
in this case. You can see angular's implementation of $http which includes $apply
.