I'm writting an angularjs app with PouchDB. I can't get updated template after query from db.
I loaded data from XML2JSON, then put them to pouchdb. Here is the deal.
If I use this to fill data to view, every think is OK.
$http.get('Katalog_27_11_2014_21_41_21.xml').then(function(resp) {
console.log(resp);
return resp.data;
}).then(function(string) {
var jsonData = xmlParser.xml_str2json(string);
var outPutJSON = [];
console.log(jsonData);
angular.forEach(jsonData.Catalog.Item, function(value, key) {
Database.put(value.EANs.EAN,value);
outPutJSON.push(value);
console.log(value);
});
$scope.products = outPutJSON;
});
but if I use query from pouchdb the view is empty, I see the data in console nad even in the ng-inspector, but not in the view. I thougth that I have to user $scope.apply() for updating the view and model, but that's what i get TypeError: undefined is not a function {stack: (...), message: "undefined is not a function"}
The in view is empty. I can't figure out where is the bug... :]
Database.queryDocs().then(function(doc) {
var _products = [];
log.debug(doc);
angular.forEach(doc.rows, function(value, key) {
log.debug(value);
_products.push(value.doc.data);
});
$scope.products = _products;
// $scope.apply();
log.debug($scope.products);
})
.catch(function(argument) {
log.debug(argument);
});
UPDATE
I've added this, now it's magicly works, but still don't know why. Becouse I'm using the same in other app (Ionic) and there is working - angular 1.2.7. I'm confused. Here is 1.3.4
$scope.$apply(function(){
$scope.products = _products;
})
The digest cycle is run using $scope.$apply(), not $scope.aplly().
That was typping error here. I'm using $scope.apply();
Related
I'm trying to retrieve a list of data from mysql database by using electron and bind it to a list in the controllers scope. I'm using mysql2. Here is my controller:
$scope.carList = [];
mysql.execute("SELECT * FROM cars").spread(function(results){
$scope.carList = results;
console.log(results);
})
I do get the results back, but the in the view carList remains empty. How can I solve this problem?
I just added a button to my view and bound it to a check function like this:
$scope.check = function(){
console.log($scope.carList);
}
After I click on the button, my list in the views gets populated. Now my question would be how can I have my list populated on the start of the controller rather than wait for an event ro make it happen?
I think mysql.execute("").spread(fn) promise is not a part of the AngularJS digest cycle. You did not provide enough code to fully reproduce your problem but I think by triggering a new digest cycle it should work for you. E.g. try it with $timeout which triggers a new digest cycle.
$scope.carList = [];
mysql.execute("SELECT * FROM cars").spread(function(results){
$timeout(function () {
$scope.carList = results;
});
})
I would prefer to create a AngularJS service which handles your electron mysql in a nice way. You could globally apply your $scopes in it, right after finishing your mysql procedures which are not a part of your digest cycle.
Approach by using AngularJS promises
var myApp = angular.module('myApp', []);
myApp.controller('MyCtrl', function($scope, $q) {
$scope.carList = [];
getCars.then(function(cars) {
$scope.carList = cars;
});
function getCars() {
var deferred = $q.defer();
mysql.execute("SELECT * FROM cars").spread(function(results) {
deferred.resolve(results);
});
return deferred.promise;
}
});
It seems to be very very simple. But I can't do it.
I just want to get a value of my Firebase DB in my controller.
The Firebase Database is like this:
users {
30549545 {
name: "Marcelo"
lastName: "Forclaz"
years: 24
}
}
In my controller I wrote the following code:
app.controller('usersCtrl', function($scope, $firebaseArray) {
var ref = firebase.database().ref('users');
$scope.userdata = $firebaseArray(ref);
});
In the ngRepeat of the HTML code the iteration works fine. But I need to get the "years" value in my controller to use it to another command, ¿How can I do it? I've tried of several deferents ways but I didn't get the wished result. I realized that retrieving data from Firebase width AngularJS is not so easy than make it width simple and pure JavaScript.
You have to wait until userdata loaded:
app.controller('usersCtrl', function($scope, $firebaseArray) {
var ref = firebase.database().ref('users');
$scope.userdata = $firebaseArray(ref);
$scope.userdata.$loaded()
.then(function(){
console.log($scope.userdata);
});
});
Finally, I've got it!
$scope.userdata.$ref().once('value', function(snap) {
angular.forEach(snap.val(), function(index)) {
console.log(index.years)
}
}
I am trying to implement a simple bootstrap typeahead where the response is getting fetched via a http call.I am receiving the response perfectly but it seems the latest value from the service call is not getting bound to scope variable from which typeahead is reading.
$scope.onChangeCallBack = function(viewValue) {
var program = $scope.program.name;
var occupancyType = $scope.occupancyType.name;
var isStorage = $scope.isBuildingStorage;
var isFranchise = $scope.isFranchise;
var isLeased = $scope.isLeased;
var isBarBuilding=$scope.isBarBuilding;
console.log("program:"+program+"//occupancyType:"+occupancyType+"//isStorage:"+isStorage+"//isFranchise:"+isFranchise+"//+isBarBuilding"+isBarBuilding+"//viewValue"+viewValue);
var param =
{
searchString: viewValue,
filterCriteria: {
isBar: true/*isBarBuilding*/,
isFranchise: false/*isFranchise*/,
isMercantile: true/*isLeased*/,
program: program,
occupancyType:"tennat"
}
}
var promise = AEBusinessOwnerService.getBuildingClassification(param);
promise.then(function(data) {
console.log(JSON.stringify(data.results));
$sccope.classificationTypeAhead = data.results;
});
};
The search result that get displayed after 4 words are keyed in is visible only after typing the 5th character.I am not sure whats missing.
If I had to guess, I'd guess that AEBusinessOwnerService.getBuildingClassification isn't returning a promise that's integrated with Angular's digest cycle (ie. something based on $q). Try doing this:
promise.then(function(data) {
$scope.$apply(function() {
console.log(JSON.stringify(data.results));
$scope.classificationTypeAhead = data.results;
});
});
This is a supporting answer to Jonathan's but I can't comment yet so:
promise.then(function(data) {
$scope.$apply(function() {
console.log(JSON.stringify(data.results));
$scope.classificationTypeAhead = data.results;
});
});
If I do as above i get the error as Error: [$rootScope:inprog] $digest
already in progress
As the error stated, a $digest is in progress, you can solve it by doing this
if(!$scope.$$phase) {
$scope.$apply(function() {
console.log(JSON.stringify(data.results));
$scope.classificationTypeAhead = data.results;
});
}
I am working on displaying collection that I got from DB in angular with firebase DB. I have those controller and service setup. in the html, I use search.users expecting it will hold all the data that I got from the DB but it won't show up. I can't figure out why. I tried few things like angular.copy or $broadcast with no luck. Can anyone help advise on this? Appreciated in advance.
.controller('SearchController', function ($scope, SearchService, logout, $location){
var search = this;
search.users = SearchService.users;
//$scope.$on('evtputUsers', function () {
// search.users = SearchService.users;
//});
})
//service for SearchService
.factory('SearchService', function ($http, $rootScope){
var userRef = new Firebase("app url");
var broadcastUsers = function () {
$rootScope.$broadcast('evtputUsers');
};
//get the user info
//insert the data to the db.
//retrieving the data
var dbUsers;
userRef.child('users').on('value', function(snapshot){
dbUsers = snapshot.val();
// angular.copy(snapshot.val(), dbUsers);
console.log('usersinDB:',dbUsers);
broadcastUsers();
}, function(err){
console.error('an error occured>>>', err);
});
return {
users: dbUsers
};
})
Rather than using $broadcast() and $on() you should use the AngularFire module.
AngularFire provides you with a set of bindings to synchronizing data in Angular.
angular.module('app', ['firebase']) // 1
.controller('SearchCtrl', SearchCtrl);
function SearchCtrl($scope, $firebaseArray) {
var userRef = new Firebase("app url")
$scope.users = $firebaseArray(userRef); // 2
console.log($scope.users.length); // 3
}
There are three important things to take note of:
You need to include AngularFire as firebase in the dependency array.
The $firebaseArray() function will automagically synchronize your user ref data into an array. When the array is updated remotely it will trigger the $digest() loop for you and keep the page refreshed.
This array is asynchronous. It won't log anything until data has populated it. So if you're logs don't show anything initially, this is because the data is still downloading over the network.
I have trouble fetching one unique item from my firebase using angularfire 1.0.0. To clarify, I want my app to fetch a post given a unique firebase id e.g. "-JkZwz-tyYoRLoRqlI_I". It works when navigating in the app e.g. clicking on a link to a specific post, but not on a refresh. My guess is that it has something to do with synchronization. Right now it works when fetching all posts and use it in a ng-repeat. This is a clue to why it works for one item when navigating to the page. This should probably not be hard since this should be a pretty standard operation, but i can't get it to work. I have searched everywhere but there is actually no guide on this. In the API they refer to $getRecord(key)
Returns the record from the array for the given key. If the key is not
found, returns null. This method utilizes $indexFor(key) to find the
appropriate record.
But this is not working as expected. Or am i missing something?
It works for ng-repeat like this:
<div ng-repeat="postt in posts">
<div>
<h1>{{postt.title}}</h1>
<div>{{postt.timestamp}}</div>
<div>{{postt.content}}</div>
</div>
</div>
But not for unique items like this:
<div>
<h1>{{post.title}}</h1>
<div>{{post.timestamp}}</div>
<div>{{post.content}}</div>
</div>
This is the service:
'use strict';
angular.module('app.module.blog.post')
.factory("PostService", ["$firebaseArray", "FIREBASE_URL", function($firebaseArray, FIREBASE_URL) {
var ref = new Firebase(FIREBASE_URL + "posts");
var posts = $firebaseArray(ref);
return {
all: posts, // ng-repeat on this works fine
last: function(nr) {
var query = ref.orderByChild("timestamp").limitToLast(nr);
return $firebaseArray(query); // ng-repeat on this work fine to
},
create: function (post) {
return posts.$add(post);
},
get: function (postId) {
console.log(postId); // This is -JkZwz-tyYoRLoRqlI_I
var post = posts.$getRecord(postId);
console.log(post); // This print null
return post;
},
delete: function (post) {
return posts.$remove(post);
}
};
}]);
As the comments say in the get function, the postId is there and posts is also set, but the post is null.
This is the controller
'use strict';
angular.module('app.module.blog.post', [])
.controller('PostCtrl', ['$scope', '$routeParams', 'PostService', function($scope, $routeParams, PostService) {
// This returns e.g. postId "-JkZwz-tyYoRLoRqlI_I"
console.log($routeParams.postId);
$scope.post = PostService.get($routeParams.postId);
$scope.posts = PostService.all; // Illustrates the example not actually in this controller otherwise
}]);
This is what is an example on what is in the firebase database
<myfirebase>
posts
-JkUnVsGnCqbAxbMailo
comments
content: ...
timestamp: ...
title: ...
-JkZwz-tyYoRLoRqlI_I
comments
content: ...
timestamp: ...
title: ...
-JkhaEf9tQy06cOF03Ts
content: ...
timestamp: ...
title: ...
I find this problem very wierd since it should be very standard. I am obviously missing something, but can't work it out. Any help is very much appreciated!
Thanks in advance!
I know that the documentation of the $getRecord() function is kind of misleading. What you actually get from $firebaseArray is a promise of an array. It means that your posts variable will contain your posts at some point in the future. That being said, it seems that the $getRecord function only works when the promise have been resolved, i.e. when the array has been downloaded from Firebase. To make sure that the promise is resolved when you call the $getRecord function, you can use $loaded() on the promise :
var posts = $firebaseArray(ref);
posts.$loaded().then(function(x) {
var post = x.$getRecord(postId);
console.log(post);
}).catch(function(error) {
console.log("Error:", error);
});
If you are wondering why it works for ng-repeat, it's because Angular knows that the posts variable is a promise and waits for it to be resolved before rendering the values.
This is happening due to promises.
Along the lines of what Kato, Jean-Philippe said, $firebaseArray is not immediately available as it needs to be downloaded.
See the .$loaded() documentation:
.$loaded() "returns a promise which is resolved when the initial array data has been downloaded from Firebase. The promise resolves to the $firebaseArray itself."
That answers your question, and I just wanted to show another way of doing it:
This is a great use case for extending AngularFire services.
As the AngularFire API Documentation says:
"There are several powerful techniques for transforming the data downloaded and saved by $firebaseArray and $firebaseObject. These techniques should only be attempted by advanced Angular users who know their way around the code."
Putting all that together, you accomplish what you want to do by:
Extending the Firebase service $firebaseArray
Following the documentation for extending services.
Example
Here is a working JSFIDDLE example I put together that is tied to one of my public Firebase instances.
It's important to note that you should add ".indexOn":"timestamp" to your rules for /posts.
Factories
app.factory('PostsArray', function (FBURL, PostsArrayFactory) {
return function (limitToLast) {
if (!limitToLast) {
console.error("Need limitToLast");
return null;
}
var postsRef = new Firebase(FBURL + '/posts').orderByChild('timestamp').limitToLast(limitToLast);
return new PostsArrayFactory(postsRef);
}
});
app.factory('PostsArrayFactory', function ($q, $firebaseArray) {
return $firebaseArray.$extend({
getPost: function (postKey) {
var deferred = $q.defer();
var post = this.$getRecord(postKey);
if (post) {
console.log("Got post", post);
deferred.resolve(post);
} else {
deferred.reject("Post with key:" + postKey + " not found.");
}
return deferred.promise;
},
createPost: function (post) {
var deferred = $q.defer();
post.timestamp = Firebase.ServerValue.TIMESTAMP;
this.$add(post).then(function (ref) {
var id = ref.key();
console.log("added post with id", id, "post:", post);
deferred.resolve(ref);
}).
catch (function (error) {
deferred.reject(error);
});
return deferred.promise;
}
});
});
Controller
app.controller("SampleController", function ($scope, PostsArray) {
var posts = new PostsArray(5);
$scope.posts = posts;
$scope.newPost = {};
$scope.createNewPost = function () {
posts.createPost($scope.newPost);
}
$scope.postId = '';
$scope.getPost = function () {
posts.getPost($scope.postId).then(function (post) {
$scope.gotPost = post;
}).
catch (function (error) {
$scope.gotPost = error;
});
}
});