在 angularfire 1.0.0 中通过唯一的 firebase id 获取项目
Fetching item by unique firebase id in angularfire 1.0.0
我无法使用 angularfire 1.0.0 从我的 firebase 获取一个独特的项目。为了澄清,我希望我的应用程序在给定唯一的 firebase id 的情况下获取 post,例如“-JkZwz-tyYoRLoRqlI_I”。它在应用程序中导航时有效,例如单击 link 到特定的 post,而不是刷新。我的猜测是它与同步有关。现在它在获取所有 posts 并在 ng-repeat 中使用它时有效。这是为什么它在导航到页面时适用于一个项目的线索。这应该不难,因为这应该是一个非常标准的操作,但我无法让它工作。我到处搜索,但实际上没有这方面的指南。在 API 他们指的是 $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.
但这没有按预期工作。还是我遗漏了什么?
它适用于 ng-repeat,如下所示:
<div ng-repeat="postt in posts">
<div>
<h1>{{postt.title}}</h1>
<div>{{postt.timestamp}}</div>
<div>{{postt.content}}</div>
</div>
</div>
但不适用于像这样的独特物品:
<div>
<h1>{{post.title}}</h1>
<div>{{post.timestamp}}</div>
<div>{{post.content}}</div>
</div>
这是服务:
'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);
}
};
}]);
正如 get 函数中的评论所说,postId 在那里,posts 也已设置,但 post 为空。
这是控制器
'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
}]);
这是关于 firebase 数据库内容的示例
<myfirebase>
posts
-JkUnVsGnCqbAxbMailo
comments
content: ...
timestamp: ...
title: ...
-JkZwz-tyYoRLoRqlI_I
comments
content: ...
timestamp: ...
title: ...
-JkhaEf9tQy06cOF03Ts
content: ...
timestamp: ...
title: ...
我觉得这个问题很奇怪,因为它应该是非常标准的。我显然遗漏了一些东西,但无法解决。非常感谢任何帮助!
提前致谢!
我知道$getRecord() function is kind of misleading. What you actually get from $firebaseArray
is a promise一个数组的文档。这意味着您的 posts
变量将在将来的某个时间点包含您的帖子。话虽这么说,似乎 $getRecord
函数仅在承诺已解决时才起作用,即当数组已从 Firebase 下载时。为确保在调用 $getRecord
函数时承诺得到解决,您可以在承诺上使用 $loaded()
:
var posts = $firebaseArray(ref);
posts.$loaded().then(function(x) {
var post = x.$getRecord(postId);
console.log(post);
}).catch(function(error) {
console.log("Error:", error);
});
如果您想知道为什么它适用于 ng-repeat
,那是因为 Angular 知道 posts
变量是一个承诺,并在呈现值之前等待它被解析。
这是由于承诺而发生的。
- 按照 Jean-Philippe 加藤所说的,
$firebaseArray
无法立即使用,因为它需要下载。
- 请参阅
.$loaded()
文档:
.$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:
- 这是扩展 AngularFire 服务的一个很好的用例。
- 正如 AngularFire API Documentation 所说:
"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
- 这是我放在一起的工作 JSFIDDLE example,它与我的 public Firebase 实例之一相关联。
- 请务必注意,您应该将
".indexOn":"timestamp"
添加到 /posts
的规则中。
工厂
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;
}
});
});
控制器
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;
});
}
});
我无法使用 angularfire 1.0.0 从我的 firebase 获取一个独特的项目。为了澄清,我希望我的应用程序在给定唯一的 firebase id 的情况下获取 post,例如“-JkZwz-tyYoRLoRqlI_I”。它在应用程序中导航时有效,例如单击 link 到特定的 post,而不是刷新。我的猜测是它与同步有关。现在它在获取所有 posts 并在 ng-repeat 中使用它时有效。这是为什么它在导航到页面时适用于一个项目的线索。这应该不难,因为这应该是一个非常标准的操作,但我无法让它工作。我到处搜索,但实际上没有这方面的指南。在 API 他们指的是 $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.
但这没有按预期工作。还是我遗漏了什么?
它适用于 ng-repeat,如下所示:
<div ng-repeat="postt in posts">
<div>
<h1>{{postt.title}}</h1>
<div>{{postt.timestamp}}</div>
<div>{{postt.content}}</div>
</div>
</div>
但不适用于像这样的独特物品:
<div>
<h1>{{post.title}}</h1>
<div>{{post.timestamp}}</div>
<div>{{post.content}}</div>
</div>
这是服务:
'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);
}
};
}]);
正如 get 函数中的评论所说,postId 在那里,posts 也已设置,但 post 为空。
这是控制器
'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
}]);
这是关于 firebase 数据库内容的示例
<myfirebase>
posts
-JkUnVsGnCqbAxbMailo
comments
content: ...
timestamp: ...
title: ...
-JkZwz-tyYoRLoRqlI_I
comments
content: ...
timestamp: ...
title: ...
-JkhaEf9tQy06cOF03Ts
content: ...
timestamp: ...
title: ...
我觉得这个问题很奇怪,因为它应该是非常标准的。我显然遗漏了一些东西,但无法解决。非常感谢任何帮助!
提前致谢!
我知道$getRecord() function is kind of misleading. What you actually get from $firebaseArray
is a promise一个数组的文档。这意味着您的 posts
变量将在将来的某个时间点包含您的帖子。话虽这么说,似乎 $getRecord
函数仅在承诺已解决时才起作用,即当数组已从 Firebase 下载时。为确保在调用 $getRecord
函数时承诺得到解决,您可以在承诺上使用 $loaded()
:
var posts = $firebaseArray(ref);
posts.$loaded().then(function(x) {
var post = x.$getRecord(postId);
console.log(post);
}).catch(function(error) {
console.log("Error:", error);
});
如果您想知道为什么它适用于 ng-repeat
,那是因为 Angular 知道 posts
变量是一个承诺,并在呈现值之前等待它被解析。
这是由于承诺而发生的。
- 按照 Jean-Philippe 加藤所说的,
$firebaseArray
无法立即使用,因为它需要下载。 - 请参阅
.$loaded()
文档:.$loaded()
"returns a promise which is resolved when the initial array data has been downloaded from Firebase. The promise resolves to the $firebaseArray itself."
- 这是扩展 AngularFire 服务的一个很好的用例。
- 正如 AngularFire API Documentation 所说:
"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."
- 正如 AngularFire API Documentation 所说:
- Putting all that together, you accomplish what you want to do by:
- Extending the Firebase service
$firebaseArray
- Following the documentation for extending services.
- Extending the Firebase service
Example
- 这是我放在一起的工作 JSFIDDLE example,它与我的 public Firebase 实例之一相关联。
- 请务必注意,您应该将
".indexOn":"timestamp"
添加到/posts
的规则中。
工厂
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;
}
});
});
控制器
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;
});
}
});