So I have this for example in firebase
clients {
//clients with unique keys {
invoices: {
// Invoices with unique Keys
}
}
}
I'm returning all this with one ref like so:
.controller('singleClientController', function($scope, $firebaseObject, fbUrl, $routeParams) {
var id = $routeParams.id;
var singleRef = new Firebase(fbUrl+'/clients/'+id);
var client = this;
client.details = $firebaseObject(singleRef);
})
so in my html, I'm trying to return the $id
for both the client and the invoice. I am able to get the client no problem with {{client.details.$id}}
but when I try to do the same thing with the invoice id {{invoice.$id}}
I don't get anything.
The invoices are displayed through a foreach like so:
<tr ng-repeat="invoice in client.details.invoices">
<td>
<a href="#/invoices/details/{{invoice.$id}}/{{client.details.$id}}">
{{invoice.settings.number}}
</a>
</td>
...
</tr>
Is it because the invoices are inside the client? If so, how would you return the id for the invoices? It's driving me nuts! Please help!
For a better understanding of my firebase set-up here is a screenshot of what I'm talking about.
tl;dr - In Firebase it is ideal to have a flat data structure.
JSBin Example
In your case you have invoices nested under clients.
{
"clients": {
"1": {
"name": "Alison",
"invoices": {
"0001": {
"amount": 500
"paid": true
}
}
}
}
}
This feels natural because the invoices are nicely grouped underneath the proper client. However, this can lead to bad performance in syncing data with Firebase. Firebase reads all data underneath a node.
This means every time you read /clients/1
you also get the invoices downloaded over the network. Even if you just need the client's name, you'll also get the the invoices.
The solution is to flatten your data structure.
{
"clients": {
"1": {
"name": "Alison"
}
},
"clientInvoices": {
"1": {
"0001": {
"amount": 500
"paid": true
}
}
}
}
The important part to grasp here is the shared key.
In this example the key is 1
. This is for simplicity. In reality you'll likely use a .push()
id.
By using this pattern you'll still be able to retrieve all of the invoices for the client by simply knowing their key. This also decouples the client from the invoices.
As an added benefit your controller code and ng-repeat
will be much easier.
In your case you should switch from a $firebaseObject
to a $firebaseArray
for the invoices. We can even create a helper factory that gets the invoices by a client's id.
.factory('invoices', function(fbUrl, $firebaseArray) {
return function(clientId) {
var ref = new Firebase(fbUrl).child('clientInvoices').child(clientId);
return $firebaseArray(ref);
}
})
// While we're at it, lets create a helper factory for retrieving a
// client by their id
.factory('clients', function(fbUrl, $firebaseObject) {
return function(clientId) {
var ref = new Firebase(fbUrl).child('clients').child(clientId);
return $firebaseObject(ref);
}
})
Now inject the helper factories into your controller and use the $routeParams.id
to retrieve the client's invoices:
.controller('singleClientController', function($scope, $routeParams, invoices, clients) {
$scope.client = clients($routeParams.id);
$scope.clientInvoices = invoices($routeParams.id);
})
Now binding it to your template is a breeze:
<tr ng-repeat="invoice in clientInvoices">
<td>
<a href="#/invoices/details/{{invoice.$id}}/{{client.$id}}">
{{invoice.settings.number}}
</a>
</td>
...
</tr>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With