在 value/key 上加入 AngularFire 路径不起作用(将用户配置文件合并到记录中)
Joining AngularFire paths on a value/key is not working (merging user profiles into records)
我正在使用 Firebase (1.0) 和 Angular (1.4) 开发应用程序。我遇到的问题是确保视图中的数据与 Firebase 同步,同时从 Firebase 中的两个 tables 获取非规范化数据:
这本书 table 看起来像这样:
books:
-JyDpkQrUozE3L7flpo: {
title: "title1",
author: {-JyDpkQrUozE3L7fl1x: true}
},
-JyDpkQrUozE3L7flp1: {
title: "title2",
author: {-JyDptrrrezE3L7flKx: true}
},
-JyDpkQrUozE3L7flp2: {
title: "title3",
author: {-JyDpkQrUozE3L7f222: true}
}
作者table长这样:
authors:
-JyDpkQrUozE3L7flKx: {
firstname: "jacques",
lastname: "smith"
},
-JyDptrrrezE3L7flKx: {
firstname: "bill",
lastname: "halley"
},
-JyDpkQrUozE3L7f222: {
firstname: "john",
lastname: "ford"
}
我的控制器是这样的:
.controller('booksController', ['$scope', '$firebaseArray', function($scope, $firebaseArray) {
var ref = new Firebase("https://[PATH].firebaseio.com/";
$scope.bookList = $firebaseArray(ref.child('books'));
$scope.authorList = $firebaseArray(ref.child('authors'));
$scope.getAuthor = function(id) {
return $scope.authorList.$getRecord(id);
};
});
我的 html 看起来像这样:
<pre>
<p ng-repeat="book in books" ng-init="author = getAuthor(book.author)">
The author of {{book.title}} is {{author.firstName}} {{author.lastName}}.
</p>
</pre>
上面的期望输出应该是:"The author of title1 is Jacques Smith. The author of title2 is Bill Halley ..."。然而,我得到的是:"The author of title 1 is. The author of title2 is..." 所以作者在我的 html returns 中一片空白。
有什么想法吗?
我看到的是您的 json 书籍数据将作者作为对象。这是传递给 $getRecord 的内容 method.The 作者的 ID 是键,而不是值。
我相信如果你像这样构建你的数据:
books: {
-JyDpkQrUozE3L7flpo: {
title: "title1",
author: "-JyDpkQrUozE3L7fl1x"
}
-JyDpkQrUozE3L7flp1: {
title: "title2",
author: "-JyDptrrrezE3L7flKx"
},
-JyDpkQrUozE3L7flp2: {
title: "title3",
author: "-JyDpkQrUozE3L7f222"
}
应该可以的,但是好久没用firebase了
Brandon 的回答是对所提出问题的技术正确回答。我将详细说明加入这些记录的更好方法。
其实我已经回答了this exact question in a fiddle, and also provided a more sophisticated, elegant, and simpler solution of how to cache and merge user profiles into objects。我将在这里重申其工作原理的细节。
app.factory('NormalizedPosts', function($firebaseArray, userCache) {
var PostsWithUsers = $firebaseArray.$extend({
// override $$added to include users
$$added: function(snap) {
// call the super method
var record = $firebaseArray.prototype.$$added.call(this, snap);
userCache.$load( record.user ).$loaded(function( userData ) {
record.userData = userData;
});
// return the modified record
return record;
}
});
return PostsWithUsers;
});
这里我决定使用缓存的用户列表,因为它们很可能是高度冗余的,这提供了一种使所有内容保持同步的优雅方式。这不是绝对必要的——我们可以在 $$added 中查找它们,但这会留下一些边缘情况需要处理。所以同步用户的缓存感觉就在这里。
缓存实用程序如下:
app.factory('userCache', function ($firebase) {
return function (ref) {
var cachedUsers = {};
// loads one user into the local cache, you do not need to
// wait for this to show it in your view, Angular and Firebase
// will work out the details in the background
cachedUsers.$load = function (id) {
if( !cachedUsers.hasOwnProperty(id) ) {
cachedUsers[id] = $firebaseObject(ref.child(id));
}
return cachedUsers[id];
};
// frees memory and stops listening on user objects
// use this when you switch views in your SPA and no longer
// need this list
cachedUsers.$dispose = function () {
angular.forEach(cachedUsers, function (user) {
user.$destroy();
});
};
// removes one user, note that the user does not have
// to be cached locally for this to work
cachedUsers.$remove = function(id) {
delete cachedUsers[id];
ref.child(id).remove();
};
return cachedUsers;
}
});
这里是 a gist putting it all together。
注意,如果我们知道当我们的控制器被销毁时,数据将不再有用,我们可以通过调用 $destroy
来清理监听器和内存。这不是绝对必要的,可能是过早的优化,但对于拥有需要跟踪数万条记录的复杂生产应用程序的用户来说,可能值得一提:
app.controller('...', function(NormalizedPosts, userCache, $scope) {
$scope.posts = new NormalizedPosts(<firebase ref>);
$scope.$on('$destroy', function() {
$scope.posts.$destroy();
userCache.$dispose();
});
});
我意识到这是一个老问题,但我想我将我的解决方案分享给那些仍在谷歌搜索的人。
就像 Brandon 提到的那样,您不应该将作者作为对象,而只是 ID(参考)
您的数据应如下所示:
{
books: {
JyDpkQrUozE3L7flpo: {
title: "title1",
authorId: JyDpkQrUozE3L7fl1x
},
JyDpkQrUozE3L7flp1: {
title: "title2",
authorId: JyDptrrrezE3L7flKx
},
JyDpkQrUozE3L7flp2: {
title: "title3",
authorId: JyDpkQrUozE3L7f222
}
},
authors: {
JyDpkQrUozE3L7flKx: {
firstname: "jacques",
lastname: "smith"
},
JyDptrrrezE3L7flKx: {
firstname: "bill",
lastname: "halley"
},
JyDpkQrUozE3L7f222: {
firstname: "john",
lastname: "ford"
}
}
}
请注意,我将 author 更改为 authorId 以更明确地说明什么是 authoer 对象以及什么只是 id。现在让我们获取所有的书和作者。
app.factory('BooksWithAuthor', function($firebaseArray, $firebaseObject) {
const books = firebase.database().ref('books')
const authors = firebase.database().ref('authors');
const bookList = $firebaseArray.$extend({
$$added: function(snap) {
const book = $firebaseArray.prototype.$$added.call(this, snap);
book.author = $firebaseObject(authors.child(book.authorId));
return record;
}
});
return new bookList(books)
});
app.controller('BookCtrl, function(BooksWithAuthor) {
$scope.BookList = BooksWithAuthor;
});
然后在你的HTML中做
<div ng-repeat="book in booklist">
{{ book.title }} was written by {{ book.author.firstname }} {{ book.author.lastname }}
</div>
我正在使用 Firebase (1.0) 和 Angular (1.4) 开发应用程序。我遇到的问题是确保视图中的数据与 Firebase 同步,同时从 Firebase 中的两个 tables 获取非规范化数据:
这本书 table 看起来像这样:
books: -JyDpkQrUozE3L7flpo: { title: "title1", author: {-JyDpkQrUozE3L7fl1x: true} }, -JyDpkQrUozE3L7flp1: { title: "title2", author: {-JyDptrrrezE3L7flKx: true} }, -JyDpkQrUozE3L7flp2: { title: "title3", author: {-JyDpkQrUozE3L7f222: true} }
作者table长这样:
authors: -JyDpkQrUozE3L7flKx: { firstname: "jacques", lastname: "smith" }, -JyDptrrrezE3L7flKx: { firstname: "bill", lastname: "halley" }, -JyDpkQrUozE3L7f222: { firstname: "john", lastname: "ford" }
我的控制器是这样的:
.controller('booksController', ['$scope', '$firebaseArray', function($scope, $firebaseArray) { var ref = new Firebase("https://[PATH].firebaseio.com/"; $scope.bookList = $firebaseArray(ref.child('books')); $scope.authorList = $firebaseArray(ref.child('authors')); $scope.getAuthor = function(id) { return $scope.authorList.$getRecord(id); }; });
我的 html 看起来像这样:
<pre>
<p ng-repeat="book in books" ng-init="author = getAuthor(book.author)">
The author of {{book.title}} is {{author.firstName}} {{author.lastName}}.
</p>
</pre>
上面的期望输出应该是:"The author of title1 is Jacques Smith. The author of title2 is Bill Halley ..."。然而,我得到的是:"The author of title 1 is. The author of title2 is..." 所以作者在我的 html returns 中一片空白。
有什么想法吗?
我看到的是您的 json 书籍数据将作者作为对象。这是传递给 $getRecord 的内容 method.The 作者的 ID 是键,而不是值。
我相信如果你像这样构建你的数据:
books: {
-JyDpkQrUozE3L7flpo: {
title: "title1",
author: "-JyDpkQrUozE3L7fl1x"
}
-JyDpkQrUozE3L7flp1: {
title: "title2",
author: "-JyDptrrrezE3L7flKx"
},
-JyDpkQrUozE3L7flp2: {
title: "title3",
author: "-JyDpkQrUozE3L7f222"
}
应该可以的,但是好久没用firebase了
Brandon 的回答是对所提出问题的技术正确回答。我将详细说明加入这些记录的更好方法。
其实我已经回答了this exact question in a fiddle, and also provided a more sophisticated, elegant, and simpler solution of how to cache and merge user profiles into objects。我将在这里重申其工作原理的细节。
app.factory('NormalizedPosts', function($firebaseArray, userCache) {
var PostsWithUsers = $firebaseArray.$extend({
// override $$added to include users
$$added: function(snap) {
// call the super method
var record = $firebaseArray.prototype.$$added.call(this, snap);
userCache.$load( record.user ).$loaded(function( userData ) {
record.userData = userData;
});
// return the modified record
return record;
}
});
return PostsWithUsers;
});
这里我决定使用缓存的用户列表,因为它们很可能是高度冗余的,这提供了一种使所有内容保持同步的优雅方式。这不是绝对必要的——我们可以在 $$added 中查找它们,但这会留下一些边缘情况需要处理。所以同步用户的缓存感觉就在这里。
缓存实用程序如下:
app.factory('userCache', function ($firebase) {
return function (ref) {
var cachedUsers = {};
// loads one user into the local cache, you do not need to
// wait for this to show it in your view, Angular and Firebase
// will work out the details in the background
cachedUsers.$load = function (id) {
if( !cachedUsers.hasOwnProperty(id) ) {
cachedUsers[id] = $firebaseObject(ref.child(id));
}
return cachedUsers[id];
};
// frees memory and stops listening on user objects
// use this when you switch views in your SPA and no longer
// need this list
cachedUsers.$dispose = function () {
angular.forEach(cachedUsers, function (user) {
user.$destroy();
});
};
// removes one user, note that the user does not have
// to be cached locally for this to work
cachedUsers.$remove = function(id) {
delete cachedUsers[id];
ref.child(id).remove();
};
return cachedUsers;
}
});
这里是 a gist putting it all together。
注意,如果我们知道当我们的控制器被销毁时,数据将不再有用,我们可以通过调用 $destroy
来清理监听器和内存。这不是绝对必要的,可能是过早的优化,但对于拥有需要跟踪数万条记录的复杂生产应用程序的用户来说,可能值得一提:
app.controller('...', function(NormalizedPosts, userCache, $scope) {
$scope.posts = new NormalizedPosts(<firebase ref>);
$scope.$on('$destroy', function() {
$scope.posts.$destroy();
userCache.$dispose();
});
});
我意识到这是一个老问题,但我想我将我的解决方案分享给那些仍在谷歌搜索的人。
就像 Brandon 提到的那样,您不应该将作者作为对象,而只是 ID(参考)
您的数据应如下所示:
{
books: {
JyDpkQrUozE3L7flpo: {
title: "title1",
authorId: JyDpkQrUozE3L7fl1x
},
JyDpkQrUozE3L7flp1: {
title: "title2",
authorId: JyDptrrrezE3L7flKx
},
JyDpkQrUozE3L7flp2: {
title: "title3",
authorId: JyDpkQrUozE3L7f222
}
},
authors: {
JyDpkQrUozE3L7flKx: {
firstname: "jacques",
lastname: "smith"
},
JyDptrrrezE3L7flKx: {
firstname: "bill",
lastname: "halley"
},
JyDpkQrUozE3L7f222: {
firstname: "john",
lastname: "ford"
}
}
}
请注意,我将 author 更改为 authorId 以更明确地说明什么是 authoer 对象以及什么只是 id。现在让我们获取所有的书和作者。
app.factory('BooksWithAuthor', function($firebaseArray, $firebaseObject) {
const books = firebase.database().ref('books')
const authors = firebase.database().ref('authors');
const bookList = $firebaseArray.$extend({
$$added: function(snap) {
const book = $firebaseArray.prototype.$$added.call(this, snap);
book.author = $firebaseObject(authors.child(book.authorId));
return record;
}
});
return new bookList(books)
});
app.controller('BookCtrl, function(BooksWithAuthor) {
$scope.BookList = BooksWithAuthor;
});
然后在你的HTML中做
<div ng-repeat="book in booklist">
{{ book.title }} was written by {{ book.author.firstname }} {{ book.author.lastname }}
</div>