1

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 ?

4
  • Can you show some code of your filter? Commented Apr 26, 2016 at 13:03
  • @Fidel90 this is my only code for the filter. My $scope.folders contain an Array of Json and el.selected[0] a string Commented Apr 26, 2016 at 13:06
  • Ah, you're talking about docs.angularjs.org/api/ng/filter/filter, got it :) Commented Apr 26, 2016 at 13:10
  • try defining a custom comparator function to find if the problem is the string compare Commented Apr 26, 2016 at 13:29

2 Answers 2

1

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  
        };
    })
    
Sign up to request clarification or add additional context in comments.

Comments

0

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.

9 Comments

I just got a last tiny issue. When i Pass the third argument of your filter with my el.selected[0] which is a string it doesn't work. It's really weird cos if now I insert the third argument as you did with the value of el.selected[0] it works !
@musecz: Hmm...are you sure that your el.selected[0] holds the correct data? Where does its value come from?
el.selected is an array that I got when I click on a node from JS-Tree. in the el object I have a field like so : selected: ["/Users/Me/project/products/Poste à souder"]. It's weird cos the value is correct and the type is string
@musecz: Like in this plunker: plnkr.co/edit/jQvtYoWIsNSjKRqtmZxt?p=preview ? You can add some additional code if necessary to reproduce the problem.
Thanks. In fact I noticed that the string are identical but not their length weirdly. el.selected[0] must had a white space or something else that we can't see when we console.log it !
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.