Reputation: 1519
I got two ng-repeat who display objects call 'post', and I have a button for edit the text and update it. Everything works fine but I still got a little problem here's the html code :
<li ng-repeat="post in posts | filter: { etat: 'aTraiter' } ">
<p ng-show="!editing[$index]" ng-model href="#/{{post._id}}">{{ post.corps }}</p>
<input ng-show="editing[$index]" type="text" ng-model="post.corps">
<a ng-show="!editing[$index" ng-click="edit(post)">Editer</a>
<a ng-show="editing[$index]" ng-click="update(post)">Confirmer</a>
<a ng-show="editing[$index]" ng-click="cancel(post)">Annuler</a>
</li>
<li ng-repeat="post in posts | filter: { etat: 'enCours' } ">
<p ng-show="!editing[$index]" ng-model href="#/{{post._id}}">{{ post.corps }}</p>
<input ng-show="editing[$index]" type="text" ng-model="post.corps">
<a ng-show="!editing[$index]" ng-click="edit(post)">Editer</a>
<a ng-show="editing[$index]" ng-click="update(post)">Confirmer</a>
<a ng-show="editing[$index]" ng-click="cancel(post)">Annuler</a>
</li>
the controller :
$scope.editing = [];
$scope.posts= Posts.query();
$scope.edit = function(post){
var idx = $scope.posts.indexOf(post);
$scope.editing[idx] = angular.copy($scope.posts[idx]);
}
$scope.update = function(post){
var idx = $scope.posts.indexOf(post);
Posts.update({id: post._id}, post);
$scope.editing[idx] = false;
}
$scope.cancel = function(post){
var idx = $scope.posts.indexOf(post);
post = angular.copy(post);
$scope.editing[idx] = false;
}
If I got just one post I can edit it and all is ok.
But when I got one post in the both ng-repeat I got some bugs, if I click on edit, buttons change in the both ng-repeat and the both post can be edit.
I'm not really sure but I thinks it's a problem with my :
ng-show="editing[$index]"
I try to put the index of the post like this
ng-show="editing[posts.indexOf(post)]"
But this is not working, can somebody help me ?
(The jsfiddle link)
EDIT the post query :
Posts.query();: Array[0]
0: d
__v: 0
_id: "569563a96a81e64409623179"
corps: "asdad"
etat: "enCours"
nomReseau: "Google+"
section: "evolution"
__proto__: d
1: d
__v: 0
_id: "56954e676a81e6440962316b"
corps: "sdfsdfsf"
etat: "enCours"
nomReseau: "Google+"
section: "evolution"
__proto__: d
Upvotes: 0
Views: 751
Reputation: 3030
You're using $index, which is just ... well... an index. Both collections can have a value at index==1, right? So, $index isn't unique across the entire set of posts.
Luckily, it would appear that you have an ID for each post that seems to be unique: post._id. How about using that instead?
One little side-note - I'm using jquery's grep method below to find a post by Id. It's fine, but I like underscore.js better. Take a look at both ...
//This is me willfully and wantonly changing your variables ... sorry.
$scope.selectedPost = undefined;
$scope.selectedPost_unchanged = undefined;
//This is the same, though, so you should feel good ;-)
$scope.posts= Posts.query();
$scope.edit = function(postId){
var result = $.grep($scope.posts, function(p){ return p._id == postId; });
if(result.length==0) { return; }
//just store the one we are editing. that should be cool, right?
$scope.selectedPost = results[0];
//ok... im changing this too... see if you like it better?
//we're gonna use it in the CANCEL method (below).
$scope.selectedPost_unchanged = angular.copy(results[0]);
}
$scope.update = function(post){
Posts.update({id: post._id}, post);
$scope.selectedPost = undefined;
$scope.selectedPost_unchanged = undefined;
}
$scope.cancel = function(post){
post = angular.extend({}, $scope.selectedPost_unchanged);
$scope.selectedPost = undefined;
$scope.selectedPost_unchanged = undefined;
}
//This is new too ... just adding it so that the html is clearer.
$scope.isEditing = function(post) {
if($scope.selectedPost==undefined) { return false; }
return post._id == $scope.selectedPost._id;
}
All of your editing[$index]
code becomes just isEditing(post)
Not for nothing, but I would add the while editing/not-editing show/hide using css. Then, add an ng-class to the li element instead (eg - ng-class="{editing: isEditing(post)}"
). Then, take care of all your show/hides with css. This way, you only have to put isEditing(post) in ONE location in your html (instead of adding it to every element). ng tags are not expensive, but they REALLY add up inside of ng-repeat tags.
Upvotes: 1
Reputation: 6430
The problem with using $index, passing it to your controller and then trying to use that index to search for a 'post' in your array of posts, is that $index
references your view index and not the true index of the item in the array.
This is traditionally not a problem unless you are filtering your array with ng-repeat
. Why? Because $index does not reflex the index of the item, but the index of how the item is appearing in the DOM. So although the first rendered post could have index 5 in your posts array, it will still have $index
of 0 because it is the first rendered item in the ng-repeat
.
Controller:
$scope.posts = Posts.query();
$scope.postsATraiter = $scope.posts.filter(function(item, index) {
return item.etat === 'aTraiter';
});
$scope.postsEnCours = $scope.posts.filter(function(item, index) {
return item.etat === 'enCours';
})
$scope.edit = function(post, postType){
var idx = getPostsByType(postType).indexOf(post);
$scope.editing[idx] = angular.copy($scope.posts[idx]);
}
$scope.update = function(post, postType){
var idx = getPostsByType(postType).indexOf(post);
Posts.update({id: post._id}, post);
$scope.editing[idx] = false;
}
$scope.cancel = function(post, postType){
var idx = getPostsByType(postType).indexOf(post);
post = angular.copy(post);
$scope.editing[idx] = false;
}
function getPostsByType(postTypeString) {
if (postTypeString === 'aTraiter') {
return $scope.postsATraiter;
} else {
return $scope.postsEnCours;
}
}
Now that the data is separate you are free to use $index because we know that the $index will respect the true index of the item in the array because it is not being filtered.
<li ng-repeat="post in postsATraiter">
<p ng-show="!editing[$index]" ng-model href="#/{{post._id}}">{{ post.corps }}</p>
<input ng-show="editing[$index]" type="text" ng-model="post.corps">
<a ng-show="!editing[$index" ng-click="edit(post, 'aTraiter')">Editer</a>
<a ng-show="editing[$index]" ng-click="update(post, 'aTraiter')">Confirmer</a>
<a ng-show="editing[$index]" ng-click="cancel(post,'aTraiter')">Annuler</a>
</li>
<li ng-repeat="post in postsEnCours">
<p ng-show="!editing[$index]" ng-model href="#/{{post._id}}">{{ post.corps }}</p>
<input ng-show="editing[$index]" type="text" ng-model="post.corps">
<a ng-show="!editing[$index]" ng-click="edit(post, 'enCours')">Editer</a>
<a ng-show="editing[$index]" ng-click="update(post, 'enCours')">Confirmer</a>
<a ng-show="editing[$index]" ng-click="cancel(post, 'enCours')">Annuler</a>
</li>
You may have to fiddle around with your implementation more, but it appears that $index and the way it is being used may be the root of the problems you are having.
Upvotes: 1