fix(isArrayLike) Correctly detect arrayLike items

Change the implementation of isArrayLike to use one heavily based on the
implementation in jQuery in order to correctly detect array-like
objects, that way functionality like ngRepeat works as expected.
This commit is contained in:
Daniel Herman 2013-07-25 23:15:57 -04:00 committed by Ken Sheedlo
parent 000012f319
commit fad626f304
2 changed files with 32 additions and 12 deletions

View file

@ -80,19 +80,19 @@ var /** holds major version number for IE or NaN for real browsers */
* @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments, ...)
*/
function isArrayLike(obj) {
if (!obj || (typeof obj.length !== 'number')) return false;
// We have on object which has length property. Should we treat it as array?
if (typeof obj.hasOwnProperty != 'function' &&
typeof obj.constructor != 'function') {
// This is here for IE8: it is a bogus object treat it as array;
return true;
} else {
return obj instanceof JQLite || // JQLite
(jQuery && obj instanceof jQuery) || // jQuery
toString.call(obj) !== '[object Object]' || // some browser native object
typeof obj.callee === 'function'; // arguments (on IE8 looks like regular obj)
if (obj == null || isWindow(obj)) {
return false;
}
var length = obj.length;
if (obj.nodeType === 1 && length) {
return true;
}
return isArray(obj) || !isFunction(obj) && (
length === 0 || typeof length === "number" && length > 0 && (length - 1) in obj
);
}
/**

View file

@ -77,7 +77,27 @@ describe('ngRepeat', function() {
expect(element.find('li').length).toEqual(3);
expect(element.text()).toEqual('x;y;x;');
});
it('should iterate over an array-like class', function() {
function Collection() {}
Collection.prototype = new Array();
Collection.prototype.length = 0;
var collection = new Collection();
collection.push({ name: "x" });
collection.push({ name: "y" });
collection.push({ name: "z" });
element = $compile(
'<ul>' +
'<li ng-repeat="item in items">{{item.name}};</li>' +
'</ul>')(scope);
scope.items = collection;
scope.$digest();
expect(element.find('li').length).toEqual(3);
expect(element.text()).toEqual('x;y;z;');
});
it('should iterate over on object/map', function() {
element = $compile(