Kyle,
There seem to be a lot of very confusing and roundabout constructions here.
I'd really suggest spending some time in the AngularFire guide
<
https://www.firebase.com/docs/web/libraries/angular/guide.html>,
understanding how the lib was intended to be used, over us trying to
address all these individual errors or issues.
It would also be extremely helpful to see a smallish, working
fiddle/jsbin/et al that provides a complete picture of what we're doing
here. It's extremely difficult to guess what all these components are and
how they work together.
For example, it appears that you are loading an array into $scope.starred,
then attempting to get a record of that array out, but using the array's ID
to do it (using $indexFor(ref.name()). Also, since $loaded() does not
return a ref, this isn't going to work in any case. But since I can't tell
what this code is intending to do, I can't really recommend a fix. I also
can't tell what "show" is intended to be. Is this a boolean? A record that
exists in $scope.starred already? $save should be called only on a record
that exists in the array. It's particularly hard, starting from this
deficit, to be of much help.
To generalize, use $add on new data that does not exist in the array and
$save on existing items in the array.
Avoid unnecessary coupling (needing to check if items exist later) by using
$add the first time a record is inserted into the array. This is probably
the only appropriate time to worry about this. Call $add right then rather
than inserting it by hand by some other means like a splice or by adding
the key manually with something like $scope.starred[$scope.starred.length]
= newData.
Regards,
Kato
On Tue, Aug 12, 2014 at 10:33 AM, Kyle Pennell wrote:Thanks for that, Jacob. That does make sense so people are not
overwriting eachother.
I'm still stuck on getting the logic for when to use $add() vs. $save(). I've
been reading the docs and trying different options. How does one chain
successes and errors with the promises? I'm trying to do the logic, if
there isn't an entry for that bit of data, call $add(), if there is, call
$save().
I've tried these:
$scope.starred.$loaded()
.then(function(ref) {
var id = ref.name();
var indexnum = $scope.starred.$indexFor(id)
if(indexnum > -1){
$scope.starred.$save(angular.copy(show))
}
else {
$scope.starred.$add(angular.copy(show))
}
});
and
$scope.toggleStarred = function(show) {
show.isStarred = !show.isStarred;
$scope.starred.$save(angular.copy(show)).then(function(ref) {
var id = ref.name();
console.log("added record with id: " + id);
console.log($scope.starred.$indexFor(id));
}, function(error){
$scope.starred.$add(angular.copy(show))
});
Should I be using try catch?
Still not sure how to best implement this logic. Neither of these work.
Also, Jacob, I don't want to abuse your helpfulness. If you don't have
the time to respond in full, even just a link or hint is enough. Also, I
can ask these on stackoverflow (also) if you guys want to have questions
answered on there.
On Monday, August 11, 2014 5:58:33 PM UTC-5, Jacob Wenger wrote:Hey Kyle,
I'm glad you got that figured out! I'll explain the reason why ref.name()
=== id here because it may help you understand a little better what
AngularFire is actually doing.
It is bad practice to store arrays in Firebase which are indexed like
array[0], array[1], etc. The reason for this is that if you have an
array with three items in it, the next available index is 3 (assuming a
0-indexed array). If two users both want to add a new item to your array at
the same time, they will both write to index 3 at the same time. This
obviously can lead to some nasty situations where one person's data get's
lost (most likely, the person who go there first is overwritten by the
person who got there second). As a result, we suggest you create arrays by
using our push() method (note that this is a Firebase method, not an
AngularFire one). This will always append to the end of the array. It
creates a special push ID (which is pretty much just a hashed timestamp)
which looks something like -J92lsp03r3t. Firebase ensures that these
items stay in the correct order.
Now, with AngularFire, when you call $add(), we essentially just do
push() internally. Then, since you may want to update the object which
you just added to the array, we fulfill the promise with a Firebase (not
a $firebase) reference to that data. Getting the name of that reference
via ref.$name() returns the random push ID of the object we just added.
Hopefully that cleared things up a bit. We prefer to keep this
explanation out of the docs since it is not really necessary and adds
complexity to the docs.
Jacob
On Mon, Aug 11, 2014 at 3:28 PM, Kyle Pennell wrote:Thanks, Jacob. Another great hint. I couldn't quite get that bit to work
so I went back to the docs and tried the example there and it seems to now
be giving me the id. I can likely use that to build the logic I was trying
to build for add()and save().
var ref = new Firebase("https://kyle.firebaseio.com/");
var starredSync = $firebase(ref.child("starred"));
$scope.starred = starredSync.$asArray();
//console.log($scope.starred);
$scope.toggleStarred = function(show) {
show.isStarred = !show.isStarred;
$scope.starred.$add(angular.copy(show)).then(function(ref) {
console.log(ref);
var id = ref.name();
console.log("added record with id: " + id);
console.log($scope.starred.$indexFor(id));
});
I console logged the promise (ref) itself. I think I've made some sense
out of it (image) but not really sure how ref.name then equals id.
Don't worry about going into all of this here. I think I have enough to
work with. Perhaps an idea to explain the promises in future documentation.
I've still got plenty to learn on promises.
<
https://www.evernote.com/shard/s209/sh/844a26c4-e367-4753-ae54-34f0440732cf/e466aafce95fa398a896590d8506efb9/res/5b3aa77b-8f2e-43b9-97bd-dc3be7ecd4b1/screenshot.png?resizeSmall&width=832>
On Monday, August 11, 2014 3:11:20 PM UTC-5, Jacob Wenger wrote:Hey Kyle,
The reason you are seeing $indexFor() return -1 is because $add()
takes some time to actually add the data to Firebase and you are logging
before that has successfully completed. Thankfully, $add() returns a
promise which you can use to wait until the operation has successfully
completed:
$scope.starred.$add(angular.copy(show)).then(function(ref) {
console.log($scope.starred.$indexFor(show));
});
If you are planning on having every user be able to star their own
items, then you probably need to restructure your data a bit. Instead of
storing an isStarred variable on each item and copying that item
everywhere, why not just add a starredItems list to each user:
{
"items": {
"-Jp29aU8S2F": {
"title": <title>,
"content": <content>,
...
},
"-Jp89a90Kq2": {
"title": <title>,
"content": <content>,
...
},
...
}
"users": {
"user1": {
"name": <name>,
"starredItems": {
"-Jp29aU8S2F": "-Jp29aU8S2F",
"-Jp89a90Kq2": "-Jp89a90Kq2",
...
}
},
...
}
}
Hopefully this will get you unstuck. Let me know if you've still got
questions.
Jacob
On Monday, August 11, 2014 11:57:35 AM UTC-7, Kyle Pennell wrote:Hey Jacob,
I've gotten decently far into implementing this code. I noticed that I
needed to change $scope.items.$save(item); to $scope.items.$add(item); in
order for it to go into my database. Then quickly I noticed that $add was
adding a new record (1 for isStarred is true, 1 for isStarred false). I
get the difference between $add and $save.
So then I reasoned that I needed some logic so that if the item is
already in the Array/Firebase, then call $save. If it's already in there,
call $add. I've been messing around trying to build if/else logic.
I read more of the $asArray documentation and saw the $indexFor(key).
So I was thinking up some logic like if $indexFor(key) > -1, call $save.
If it's greater than -1, call $add. If it's already in there, $save. If
it's not, $add it.
Does this logic make sense up to here?
But when I tried to call this bit (using $indexFor)
.controller("StarredCtrl", function($scope, $firebase) {
var ref = new Firebase("https://torid-fire-4332.firebaseio.com/");
var starredSync = $firebase(ref.child("starred"));
$scope.starred = starredSync.$asArray();
//console.log($scope.starred);
$scope.toggleStarred = function(show) {
show.isStarred = !show.isStarred;
$scope.starred.$add(angular.copy(show));
console.log($scope.starred.$indexFor(show)); // returns -1
It is adding the data into my forge here, but I don't seem to be
calling $indexFor correctly (in order to be able to put logic in). Any
ideas?
On Saturday, August 9, 2014 5:11:40 PM UTC-5, Kyle Pennell wrote:Thanks, Jacob. That's more than enough to get me started.
On Saturday, August 9, 2014 4:08:16 PM UTC-5, Jacob Wenger wrote:Hey Kyle,
I'm gonna assume you are using our new synchronized $asArray()
method in AngularFire 0.8.
<
https://www.firebase.com/docs/web/libraries/angular/api.html> If
you are still on 0.7.1, you should upgrade as this is now super easy.
You should stored your items in a Firebase ordered list (read our
docs section on this for more info
<
https://www.firebase.com/docs/web/guide/saving-data.html#section-push>),
like this:
{
"items": {
"-Jp29aU8S2F": {
"title": <title>,
"content": <content>,
"isStarred": true,
...
},
"-Jp89a90Kq2": {
"title": <title>,
"content": <content>,
"isStarred": false,
...
},
...
}
}
You can use AngularFire to sync this data to a $scope variable in
your controller like so:
sampleApp.controller("SampleCtrl", function($scope, $firebase) {
var ref = new Firebase("https://<your-firebase>.firebaseio.com/");
var itemsSync = $firebase(ref.child("items"));
$scope.items = itemsSync.$asArray();
$scope.toggleStarred = function(item) {
item.isStarred = !item.isStarred;
$scope.items.$save(item);
}
});
Then, in your view, you can add an ng-click event to your star img:
<div ng-repeat="item in items">
<p class="title">{{ item.title }}</p>
<p class="content">{{ item.content }}</p>
<img class="star" ng-click="toggleStarred(item)" />
</div>
And that's it! If you haven't already, give our new AngularFire
guide a read
<
https://www.firebase.com/docs/web/libraries/angular/guide.html>.
It will walk you through how to do stuff like this.
Jacob
On Fri, Aug 8, 2014 at 4:53 PM, Kyle Pennell <kpen...@gmail.com>
wrote:
--
You received this message because you are subscribed to the Google
Groups "Firebase + AngularJS" group.
To unsubscribe from this group and stop receiving emails from it, send
an email to firebase-angul...@googlegroups.com.
To post to this group, send email to firebase...@googlegroups.com.
To view this discussion on the web visit
https://groups.google.com/d/msgid/firebase-angular/a4029598-070f-4bca-9353-
4708a4cc993f%40googlegroups.com
<
https://groups.google.com/d/msgid/firebase-angular/a4029598-070f-4bca-9353-4708a4cc993f%40googlegroups.com?utm_medium=email&utm_source=footer>
.
For more options, visit
https://groups.google.com/d/optout. --
You received this message because you are subscribed to the Google Groups
"Firebase + AngularJS" group.
To unsubscribe from this group and stop receiving emails from it, send an
email to firebase-angular+unsubscribe@googlegroups.com.
To post to this group, send email to firebase-angular@googlegroups.com.
To view this discussion on the web visit
https://groups.google.com/d/msgid/firebase-angular/54181d5f-19a4-4c24-83d7-317fb268441b%40googlegroups.com<
https://groups.google.com/d/msgid/firebase-angular/54181d5f-19a4-4c24-83d7-317fb268441b%40googlegroups.com?utm_medium=email&utm_source=footer>
.
For more options, visit
https://groups.google.com/d/optout. --
You received this message because you are subscribed to the Google Groups "Firebase + AngularJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to firebase-angular+unsubscribe@googlegroups.com.
To post to this group, send email to firebase-angular@googlegroups.com.
To view this discussion on the web visit
https://groups.google.com/d/msgid/firebase-angular/CAFHX4%3DpCE6Y55tpbhkwW03DAsRtC%2BVkZc8GOXEULB1fkrbETmQ%40mail.gmail.com.For more options, visit
https://groups.google.com/d/optout.