Skip to content

Instantly share code, notes, and snippets.

@robbestad
Last active December 27, 2015 07:29
Show Gist options
  • Save robbestad/7289017 to your computer and use it in GitHub Desktop.
Save robbestad/7289017 to your computer and use it in GitHub Desktop.
Limit From-To filter for AngularJS
/**
* @name limitFromTo
* @by Sven Anders Robbestad, 2013
* @license CC0 1.0 Universal (CC0 1.0)
* @description
* Limit From-To filter for AngularJS.
* Creates a new array or string containing only a specified number of elements with an extra
* parameter specifying the starting point..
* The elements are taken from either the beginning or the end of the source array or string, as
* specified by the value and sign (positive or negative) of `limit`.
*
* Usage:
* <div ng-repeat="data in array|limitFromTo:2:8"></div>
* Returns a copy of the array with the remaining elements from the selected position. In the example above, the div will be populated with 6 elements from position 2.
*
*/
angular.module('myApp.filters', []).filter('limitFromTo', function() {
return function(input, offset, limit) {
if(!(input instanceof Array) && !(input instanceof String)) return input;
limit = parseInt(limit,10);
if (input instanceof String) {
if (limit) {
return limit >= 0 ? input.slice(offset, limit) : input.slice(limit, input.length);
} else {
return "";
}
}
var out = [],
i, n;
if (limit > input.length)
limit = input.length;
else if (limit < -input.length)
limit = -input.length;
if (limit > 0) {
i = offset;
n = limit;
} else {
i = input.length + limit;
n = input.length;
}
for (; i<n; i++) {
out.push(input[i]);
}
return out;
};
});
@popigg
Copy link

popigg commented Sep 19, 2014

Thanks for sharing here are some tests:

describe('LimitOffsetFilter',function(){
    beforeEach( module( 'myApp.filters' ) );

    beforeEach(
        inject(function($filter){

        createFilter = function() {
            return $filter('limitFromTo');
        }
    }));

    describe('#limitFromTo', function(){
        it('when input is not Array or String, should return input', function(){
            // given
            var result = createFilter()({key: 'value'},0,0);

            //when

            //then
            expect(result).toEqual({key: 'value'});
        });

        it('when input is String and no limit set, should return empty String', function(){
            // given
            var result = createFilter()(new String('filter'), '', '');

            //when

            //then
            expect(result).toEqual("");
        });

        it('when input is String and limit set, should return string with length equal to the sting.length - offset', function(){
            // given
            var result = createFilter()(new String('filter'), '2', '6');

            //when

            //then
            expect(result).toEqual('lter');
        });

        it('when input is Array and limit greater than input.length, should return array of elements starting from offset to end of string', function(){
            // given
            var result = createFilter()([1,2,3,4], '2', '6');

            //when

            //then
            expect(result).toEqual([3,4]);
        });

        it('when input is Array and limit lesser than (-)input.length, should return the whole input Array', function(){
            // given
            var result = createFilter()([1,2,3,4], '2', '-5');

            //when

            //then
            expect(result).toEqual([1,2,3,4]);
        });

        it('when input is Array and limit smaller than input.length, should return the input starting in the offset to limit', function(){
            // given
            var result = createFilter()([1,2,3,4], '2', '3');

            //when

            //then
            expect(result).toEqual([3]);
        })
    });
});

@andre-campos
Copy link

Thanks for sharing. I found the filter pretty useful. However, it doesn't work when the input is a string literal. In that case, the comparison using instanceof String fails. What I did instead was to add another comparison for string literals: (typeof input === "string"). That way I was able to chain the filter to the output of another filter (in my case, angular translate). Here's the full code:

app.filter('limitFromTo', function() {
    return function(input, offset, limit) {
        if(!(input instanceof Array) && !(input instanceof String) && !(typeof input === "string")) return input;

        limit = parseInt(limit,10);

        if (input instanceof String || (typeof input === "string")) {
            if (limit) {
                return limit >= 0 ? input.slice(offset, limit) : input.slice(limit, input.length);
            } else {
                return "";
            }
        }

        var out = [],
            i, n;

        if (limit > input.length)
            limit = input.length;
        else if (limit < -input.length)
            limit = -input.length;

        if (limit > 0) {
            i = offset;
            n = limit;
        } else {
            i = input.length + limit;
            n = input.length;
        }

        for (; i<n; i++) {
            out.push(input[i]);
        }

        return out;
    };
});

Cheers!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment