angular/angular.js — pull request #1661 by petebacondarwin (2012-12-06 12:39:22+00:00)
Title: ng-repeat : Fix issues when iterating over primitives

# ng-repeat Directive
This complete rewrite of ng-repeat tracks element/scope pairing for objects since they can be tracked by object identity but tracks element/scope pairings for primitive values by the index position in the collection since there is no consistent way of tracking if a primitive has moved.

## Fixes primitive issues

It solves various problems including:

* Input element losing focus on each change. See this broken Plnker based on master - http://plnkr.co/edit/bFxHW4?p=preview - and this fixed version - http://plnkr.co/edit/zh5P9Y?p=preview.
* Incorrect model updating when item is a primitive. Fixes #1389 and this fixed version of the example fiddle: http://jsfiddle.net/nMjet/

#'# Tests

I have added a new test to `ng-repeatSpec.js` to test for this but x-ed out the test that demonstrates the incorrect behaviour.

## Algorithm

The algorithm checks the following, for `original` collection and `changed` collection, at each `index`.

1. If `changed[index] === original[index]` then simply reuse element/scope pairing.
2. If both `changed[index]` and `original[index]` are primitives then leave the element alone but update the scope model. _This will trigger changes in the this iteration's template bindings and DOM. We can't try to guess if this primitive moved from elsewhere but since we are reusing the element/scope pairing there will be minimal DOM updates._
3. If a known object has moved then move its element and scope accordingly. _This reuse ensures minimal disruption to the bindings and DOM._
4. if an object moved leaving a primitive in its place then create a new element and scope for this primitive.
5. if an object moved into a position where a primitive was before, then destroy the old element/scope for that primitive.

## WhatChanged service

I factored out the algorithm that works out what has changed into its own function (`whatChanged`). Since there is potential for this to be reused, I also exposed it as a service, `$whatChanged`, in the `ng` module.

## Helper Classes

Further to facilitate repeating over object key, the whatChanged algorithm works on a "generic collection", which are created by the internal classes ArrayWrapper and ObjectWrapper. These classes expose a common API of `get(index)`, `key(index)`, `length()` and `copy()`, which allows the whatChanged algorithm to work either with a straight array or iterating over the keys of an object, cleanly. _The array wrapper is very thin and should not be a great impact on performance._

These (and a couple of other helper classes `ObjectTracker`, `ChangeTracker` and `FlattenedChanged`) can be found in `apis.js`. These new classes replace the need for HashQueueMap, which could be removed.

## To Do

There is work to be done on the documentation.

I have done no performance testing. There are more lines of code and probably in most scenarios the repeater may perform worse than before. But I reckon there is lots of room for optimization.