To learn AngularFire I’m trying to build a simple CRUD app. The INDEX and NEW pages went smoothly but I’m stuck on the SHOW and EDIT pages. I can’t get a selected record to display on the SHOW page.
With MongoDB and Angular it’s easy to make the SHOW page. On the INDEX page you put in an anchor link with the ID of the record you want to show:
<a ng-href="#/{{record._id}}"><span>{{record.title}}</span<</a>
This puts the record ID into the URL, e.g., www.website.com/#/K9hr32rhror
Then on the SHOW page you can use {{record.title}}
or {{record.author}}
or whatever you want. Angular magically remembers the ID of the record you clicked on the INDEX page. How Angular does this I have no idea. 🙂
In MongoDB the ID is called _id
. In Firebase the ID is called $id
. So I changed the code on the INDEX page to
<a ng-href="#/{{record.$id}}"><span>{{record.title}}</span<</a>
This successfully puts the ID into the URL.
The problem is that no record is displayed on the SHOW page. Angular appears to have forgotten what {{record}}
refers to.
I tried putting in a leading /
:
<a ng-href="/#/{{record._id}}"><span>{{record.title}}</span<</a>
That makes no difference.
I tried parsing the ID from the URL with
var key = location.hash.split('#/')[1]
This returns the ID. When I console.log the $firebaseArray(ref) object I see a collection (array) of all my records. But when I use collection.$getRecord(key)
or collection.$keyAt(0)
or collection.$indexFor(key)
I get null or -1, indicating that AngularFire can’t find the record.
Here’s my full controller code:
app.controller('ShowController', ['$scope', '$firebaseArray', '$location', function($scope, $firebaseArray, $location) { var ref = new Firebase("https://my-firebase.firebaseio.com/"); list = $firebaseArray(ref); console.log(list); // [] console.log(location.hash.split('#/')[1]); // -K9hr32rhror_ var key = location.hash.split('#/')[1]; console.log(list.$getRecord(key)); // null console.log(list.$keyAt(0)); // null console.log(list.$indexFor(key)); // -1
Next I tried using ng-repeat="record in collection | filter : key">
but I can’t figure out what key
should be.
I also googled “Angular Firebase CRUD SHOW page” but none of the example CRUD apps had SHOW pages. Am I misunderstanding something fundamental? E.g., should I build the SHOW and EDIT views with <ng-hide>
and <ng-show>
on the INDEX page, and not bother to make separate SHOW and EDIT pages?
Advertisement
Answer
The problem you’re dealing with is asynchronous data flow.
app.controller('ShowController', ['$scope', '$firebaseArray', '$location', function($scope, $firebaseArray, $location) { var ref = new Firebase("https://my-firebase.firebaseio.com/"); var key = location.hash.split('#/')[1]; $scope.list = $firebaseArray(ref); // data is downloading console.log($scope.list.length); // will be undefined, data is downloading $scope.list.$loaded().then(function(list) { console.log(list); // data has been downloaded! list.$getRecord(key); // data is available }); });
But .$loaded()
is usually unnecessary because AngularFire knows when to trigger $digest
. In your case you want to use a $firebaseObject
.
app.controller('ShowController', ['$scope', '$firebaseObject', '$location', function($scope, $firebaseObject, $location) { var ref = new Firebase("https://my-firebase.firebaseio.com/"); var key = location.hash.split('#/')[1]; var itemRef = ref.child(key); $scope.item = $firebaseObject(itemRef); });
This grabs the single item based off of the key
, rather than downloading the entire list and plucking out one item.