musecz
musecz

Reputation: 805

Issue using filter AngularJS

I'm using $filter to iterate through an array and fetch a specific value

Below is my code:

var selected = $filter('filter')($scope.folders, {url: el.selected[0] });

This code is working, but I got a problem when the url contain an accent and space like so :

/Users/Me/project/products/Poste à souder

In that case the string comparaison isn't working anymore.

What is the cleaner way to solve this situation ?

Upvotes: 1

Views: 172

Answers (2)

Fidel90
Fidel90

Reputation: 1838

Maybe it's best to write your own filter:

app.filter("customFilter", function () {
    //the filter will accept an input array, the key you want to look for and the value that the key should have
    return function (array, key, value) {
      return array.filter(function(x){
        return (x.hasOwnProperty(key) && (x[key] === value));
      });
    };
});

And use it in your controller like:

$scope.filtered = $filter("customFilter")($scope.folders, "url", "/Users/Me/project/products/Poste à souder");

Check out a working demo here.

Upvotes: 0

Salathiel Genese
Salathiel Genese

Reputation: 1909

That true. As a francophone, I've often encounter encoding/decoding issues with angularjs.

The source code of the default filter is as follow

function filterFilter()
{
    return function(array, expression, comparator)
    {
        if (!isArrayLike(array))
        {
            if (array == null)
            {
                return array;
            }
            else
            {
                throw minErr('filter')('notarray', 'Expected array but received: {0}', array);
            }
        }

        var expressionType = getTypeForFilter(expression);
        var predicateFn;
        var matchAgainstAnyProp;

        switch (expressionType)
        {
            case 'function':
                predicateFn = expression;
                break;
            case 'boolean':
            case 'null':
            case 'number':
            case 'string':
                matchAgainstAnyProp = true;
                //jshint -W086
            case 'object':
                //jshint +W086
                predicateFn = createPredicateFn(expression, comparator, matchAgainstAnyProp);
                break;
            default:
                return array;
        }

        return Array.prototype.filter.call(array, predicateFn);
    };
}

and the predicate generator stand as follow: it generate the default comparator if the provided one is not a function

function createPredicateFn(expression, comparator, matchAgainstAnyProp)
{
    var shouldMatchPrimitives = isObject(expression) && ('$' in expression);
    var predicateFn;

    if (comparator === true)
    {
        comparator = equals;
    }
    else if (!isFunction(comparator))
    {
        comparator = function(actual, expected)
        {
            if (isUndefined(actual))
            {
                // No substring matching against `undefined`
                return false;
            }
            if ((actual === null) || (expected === null))
            {
                // No substring matching against `null`; only match against `null`
                return actual === expected;
            }
            if (isObject(expected) || (isObject(actual) && !hasCustomToString(actual)))
            {
                // Should not compare primitives against objects, unless they have custom `toString` method
                return false;
            }

            actual = lowercase('' + actual);
            expected = lowercase('' + expected);
            return actual.indexOf(expected) !== -1;
        };
    }

    predicateFn = function(item)
    {
        if (shouldMatchPrimitives && !isObject(item))
        {
            return deepCompare(item, expression.$, comparator, false);
        }
        return deepCompare(item, expression, comparator, matchAgainstAnyProp);
    };

    return predicateFn;
}

Too much speech. You have the choice:

  1. Provide a comparator to your filter see the doc
    • but remember that you can't define inline function in angular template
    • you can define a function in that scope, but it will only be available in that scope
  2. You can write your own filter

    .filter('myCustomFilter', function()
    {
        return function(input, criteria)
        {
            ... // your logic here
            return ...// the filtered values  
        };
    })
    

Upvotes: 1

Related Questions