Firebase $remove() object from a nested array?
I can't get the Firebase $remove() method to work with nested arrays of objects. I'm making a movies database with an array of movie objects. Removing a movie from the array of movies is working:
$scope.deleteMovie = function() {
$scope.movie.$remove().then(function() {
console.log("Movie deleted.");
}, function(error) {
console.log(error);
});
};
That uses the $firebaseObject $remove() method which just hooks onto an object and removes it. The movie was identified in the array by its key, passing movie.$id into the URL and then grabbing the key from the URL to identify the movie and putting it in the $scope:
$scope.movie = $firebaseObject(ref.child($routeParams.id));
Users can add comments to movies. Each comment is an object in an array of comments. The array of comments is a property of the movie object, so it's a second-level nested array of objects. It seems like a better idea to use the $firebaseArray method $remove(recordOrIndex). I'll pass the comment through from the view:
$scope.deleteComment = function(comment) {
console.log(comment);
};
It passes through the comment:
Object {commentAuthor: "Eva Braun", commentDate: 1462461704268, commentText: "What's not to like?"}
Now I'll use $remove(comment) to delete the comment from the array:
$scope.deleteComment = function(comment) {
$scope.movie.movieComments.$remove(comment).then(function() {
console.log("Comment deleted.");
}, function(error) {
console.log(error);
});
};
The error message is "TypeError: $scope.movie.movieComments.$remove is not a function".
So $scope.movie.$remove() is a function but $scope.movie.movieComments.$remove is not a function.
I checked if this is an asynchronous problem but that doesn't seem to be the issue.
Firebase doesn't like dot notation for nested arrays of objects. I'll use the child() notation:
$scope.deleteComment = function(comment) {
$firebaseArray(ref.child($routeParams.id).child('movieComments').remove(comment)).then(function() {
console.log("Comment deleted.");
}, function(error) {
console.log(error);
});
};
The error message is "Error: Firebase.remove failed: first argument must be a valid function." The documentation says that the first argument must be either a record or an index. The comment passes through without its key, maybe that's the problem?
Let's try using an index instead of a record:
$scope.deleteComment = function(comment) {
$firebaseArray(ref.child($routeParams.id).child('movieComments').remove(0)).then(function() {
console.log("Comment deleted.");
}, function(error) {
console.log(error);
});
};
Same error message: "Error: Firebase.remove failed: first argument must be a valid function."
Let's try removing the comment from the view:
<div ng-repeat="comment in movie.movieComments">
<form>
<button ng-click="movie.movieComments.$remove(comment)">x</button>
</form>
</div>
That does nothing.
Let's try the $firebaseObject version of $remove():
$scope.deleteComment = function() {
$firebaseObject(ref.child($routeParams.id).child('movieComments').remove()).then(function() {
console.log("Comment deleted.");
}, function(error) {
console.log(error);
});
};
That works great! Except that it removes the entire array of comments, when I only want to remove one comment from the array. Let's add another .child():
$scope.deleteComment = function(comment) {
$firebaseObject(ref.child($routeParams.id).child('movieComments').child(comment).remove()).then(function() {
console.log("Comment deleted.");
}, function(error) {
console.log(error);
});
};
The error message is "Firebase.child failed: First argument was an invalid path: "undefined". Paths must be non-empty strings and can't contain ".", "#", "$", "[", or "]"".
I'm not identifying the comment correctly. How about using the key:
$scope.deleteComment = function(comment) {
console.log(comment);
$firebaseObject(ref.child($routeParams.id).child('movieComments').child(comment.$id).remove()).then(function() {
console.log("Comment deleted.");
}, function(error) {
console.log("Error, movie not deleted.");
console.log(error);
});
};
Same error message. The key isn't in the comment so the key isn't being passed through when the comment is passed through. I'll pass through the movie object and console log the movieComments array. The array has one object:
Object {-KH0VeEfwIgT1UOUrFzo: Object}
-KH0VeEfwIgT1UOUrFzo: Object
commentAuthor: "Eva Braun"
commentDate: 1462461704268
commentText: "What's not to like?"
Now I'll use $keyAt(recordOrIndex) to get the key:
$scope.deleteComment = function(movie, comment) {
console.log(movie.movieComments.$keyAt(comment));
};
"TypeError: movie.movieComments.$keyAt is not a function". Let's try .child() notation:
$scope.deleteComment = function(movie, comment) {
console.log(movie.child('movieComments').$keyAt(comment));
};
"TypeError: movie.child is not a function". Let's try that with an index number:
$scope.deleteComment = function(movie, comment) {
console.log(movie.child('movieComments').$keyAt(0));
};
"TypeError: movie.child is not a function". OK, $keyAt(recordOrIndex) and $remove(recordOrIndex) are both not working. That suggests there's something wrong with my record or index.
Any suggestions how to remove any object from a nested array in Firebase?