我开始学习很多与混合应用编码相关的东西。我决定继续使用基于AngularJS的Ionic框架(这让我有机会学习它),并使用Firebase作为我的后端解决方案。
我想在我的应用中设置地图,所以我会找到用户和他周围的一些兴趣点。我发现GeoFire已经存在,所以我开始使用它。
我的问题:我无法显示保存在Firebase中的用户位置。我使用GeoFire查询它,并获得响应(console.log),但它不会更新范围变量。
这是JS代码:
myApp.factory("MyLoc", function(){
var firebaseRef = new Firebase("https://myfirebase.firebaseio.com/geofire/");
var geoFire = new GeoFire(firebaseRef);
/* geoFire.set("user_loc", [37.785326, -122.405696]).then(function() {
console.log("Provided key has been added to GeoFire");
}, function(error) {
console.log("Error: " + error);
});*/
return geoFire.get("user_loc").then(function(location) {
if (location === null) {
console.log("Provided key is not in GeoFire");
return 0;
}
else {
console.log("Provided key has a location of " + location);
return location;
}
}, function(error) {
console.log("Error: " + error);
return 0;
});
})
myApp.controller("firstCtrl", function($scope, MyLoc) {
$scope.data = {};
$scope.data.myLoc = MyLoc;
});
HTML只显示它:
{{data.myLoc}}
因为我是Angular N00b,我想我错过了一些明显的东西。我想我应该使用承诺或类似的东西,只是无法弄清楚如何!有谁可以帮助我吗 ? :)
非常感谢兄弟们!
[UPDATE]
好的,这是第一个问题的答案!
MyLoc.then(function(data){
$scope.data.myLoc = data;
$scope.$apply();
});
但是我必须使用
$scope.$apply();
要显示HTML,显然它不会立即更新。你知道为什么吗?我理解Angular必须通知它要显示的更改,正如在此非常好地解释的那样:http://jimhoskins.com/2012/12/17/angularjs-and-apply.html
我不明白,为什么会出现这种情况?为什么Angular不知道这种变化?
再次感谢!
答案 0 :(得分:4)
Firebase的API是异步的,你被咬了。您无法以您尝试的方式从异步调用返回值:
这是您的代码的相关片段:
myApp.factory("MyLoc", function(){
var firebaseRef = new Firebase("https://myfirebase.firebaseio.com/geofire/");
var geoFire = new GeoFire(firebaseRef);
return geoFire.get("user_loc").then(function(location) {
if (location === null) {
console.log("Provided key is not in GeoFire");
return 0;
}
else {
console.log("Provided key has a location of " + location);
return location;
}
}, function(error) {
console.log("Error: " + error);
return 0;
});
})
请注意您传递给then
的那些功能?这些被称为回调函数,是Firebase(以及现代Web)的异步操作的关键。如果将这些回调提取到常规的全局命名函数中,那么更容易理解为什么你的构造不起作用:
myApp.factory("MyLoc", function(){
var firebaseRef = new Firebase("https://myfirebase.firebaseio.com/geofire/");
var geoFire = new GeoFire(firebaseRef);
return geoFire.get("user_loc").then(onGeoFireResult, onGeoFireError);
})
function onGeoFireResult(location) {
if (location === null) {
console.log("Provided key is not in GeoFire");
return 0;
}
else {
console.log("Provided key has a location of " + location);
return location;
}
}
function onGeoFireError(error) {
console.log("Error: " + error);
return 0;
}
当您致电geoFire.get("user_loc")
时,它会向服务器执行请求。该请求可能需要一些时间,我们不希望浏览器被阻止。因此,我们不是等待请求完成,而是在服务器响应请求的数据时传入一个要调用的函数。由于事情可能会出错,我们还会传入一个函数,以便在出现错误时调用。
因此,必须认识到onGeoFireResult
和onGeoFireError
的运行时间与调用geoFire.get("user_loc")
的时间不同。因此,您无法从封装函数返回结果。相反,你必须处理一个承诺的概念:一种在某些时候会有你所要求的数据的结构。
如果您想在没有AngularFire的情况下继续使用Firebase和Angular,我高度建议您按照此视频教程进行操作:https://www.youtube.com/watch?v=3YVlcFyxBr4。花一个小时左右的时间会在这里为您节省数十个问题。
或者设置两个断点:一个在onGeoFireResult
上,另一个在geoFire.get("user_loc")
之后的行上,看看哪个断点首先触发。