Discover problems
Recently, a customer complained that when deleting a specified record, the one that was deleted was another record! It looks like a very serious bug. Once we encountered this problem at work. It is very troublesome to locate this bug because the customer is not clear about how to reproduce the problem.
Later I found out that this bug was caused by using $index in ng-repeat.
A list of simple actions
Let's take a look at a complete and effective ng-repeat example.
<ul ng-controller="ListCtrl"> <li ng-repeat="item in items"> {{}} <button ng-click="remove($index)">remove</button> </li> </ul>
The corresponding controller (controller) is as follows:
('ListCtrl', ['$scope', function($scope) { //items come from somewhere, from where doesn't matter for this example $ = getItems(); $ = function(index) { var item = $[index]; removeItem(item); }; }]);
It looks like nothing wrong, right? There is nothing particularly noteworthy about this code either.
Add a filter
Then, let's make a small change: add a filter to the list. This is very common practice, if the list is long, for example, allowing users to search.
For convenience, suppose we query records in the list through searchFilter.
<ul ng-controller="ListCtrl"> <li ng-repeat="item in items | searchFilter"> {{}} <button ng-click="remove($index)">remove</button> </li> </ul>
The controller's code remains the same. It still looks like there is no problem, right?
In fact, there is a bug hidden inside. If I don't say it, can you find it? If you can find it, you are already an Angular bull.
Please try not to use $index
The bug is actually in the controller:
$ = function(index) { var item = $[index]; removeItem(item); };
The index parameter is used here, and then a bug is encountered: the filtered index (indexs) does not match the index of the original list.
Fortunately, there is a very simple way to avoid this problem: don't use $index and change it to the actual item object.
<ul ng-controller="ListCtrl"> <li ng-repeat="item in items | searchFilter"> {{}} <button ng-click="remove(item)">remove</button> </li> </ul>
The controller is as follows:
$ = function(item) { removeItem(item); };
Note that hereremove($index)
Change toremove(item)
, and modified$
Functions directly operate the object passed.
This small modification completely avoided the bug just now.
To better illustrate the problem and solution, please refer tointeractive example 。
What can you learn from this?
The first lesson is of course to be careful when using $index, as it is very likely to cause bugs when used in some ways.
The second lesson is that remember a pattern like this can be done in a better way and certain types of bugs can be completely avoided. I strongly recommend that you do not use $index now. From this simple mindset change, you can reduce many bugs in your code.
The third lesson is that testing is not useful at all times. Even if there is automated testing, it covers enough cases, but it is easy to miss certain bugs when relying on specific inputs. The error itself does not appear every time, even if you use filtering to test it.
The fourth lesson is not to destroy abstraction - this is easily overlooked. In theory, $index is a "template variable" created by ng-repeat. This only makes sense inside the repeat block (and works correctly). When we pass its value outside, it loses the context and is no longer valid. If you really want it to work outside of repeat, you must also filter in the controller, which requires some duplicate code that is not very necessary. Thankfully, the pattern described in this article can be used to avoid this.
Conclusion
The above is all the content about the precautions for using $index in ng-repeat in AngularJS practice. I hope that the content of this article will be of certain help to everyone's study or work. If you have any questions, you can leave a message to communicate.
Original link: AngularJS best practices: Be careful when using ng-repeat's $index
Original date: 2014-11-10
Translation date: 2015-01-23
Translator: Iron Anchor /renfufei