1

My custom filter should output:

Mark

...however it's outputting:

  • M
  • a
  • r
  • k

Here's my view:

  <body ng-controller="MainCtrl">
    <ul>
      <li ng-repeat="friend in friends | myFriend:currentUser">
        {{ friend }}
      </li>
    </ul>
  </body>

...and controller:

var app = angular.module('plunker', []);

app.filter('myFriend', function () {
  return function (items, currentUser) {
    console.log(items);
    console.log(currentUser);
    for (var i = 0; i < items.length; i++) {
      if (items[i] === currentUser) {
        return items[i];
      }
    }

  };
});

app.controller('MainCtrl', function($scope) {
  $scope.currentUser = 'Mark';
  $scope.friends = ['Andrew', 'Will', 'Mark', 'Alice', 'Todd'];
});

Here is my Plunker: http://plnkr.co/edit/JCKAt05MPlrvIZBCGO0n?p=preview

How can my custom filter output "Mark"?

Ryan
  • 6,027
  • 16
  • 52
  • 89

4 Answers4

2

That is because you are passing a string from the filter instead of array of string. ng-repeat will iterate though the characters (string is an array of chars) of the string Mark and display it. You need to instead pass array to ng-repeat. Filter is run first before applying source to ng-repeat. Example:

for (var i = 0; i < items.length; i++) {
  if (items[i] === currentUser) {
    return [items[i]];
  }
}

In your specific case you could just as well do as below, without creating any custom filter:

 <li ng-repeat="friend in friends | filter:currentUser:true">
  {{ friend }}
</li>
PSL
  • 123,204
  • 21
  • 253
  • 243
1

As I presume you are aware the filter is being applied to the list friends.

Your filter is returning a single string value.

Your ng-repeat can be thought of as:

ng-repeat="friend in (friends | myFriend:currentUser)"

which means you are trying to loop over the string returned by your myFriend filter. For the browser you're using ng-repeat over a string loops over each character in the string.

(Note: this might not happen on every browser, because some browsers (e.g. IE7) do not allow [] subscripting on strings. (Underneath it all, ng-repeat would rely on the value having a length property and [] subscripting.)

The following may produce the result you want (assuming you only ever want one name to be shown from the list)

  <body ng-controller="MainCtrl">
    <ul>
      <li>
        {{ friends | myFriend:currentUser }}
      </li>
    </ul>
  </body>
Community
  • 1
  • 1
Nicholas Daley-Okoye
  • 2,267
  • 1
  • 18
  • 12
1

My strong suggestion is dont write extra code. Its like reinventing the wheel. Instead stick to the general procedure and filter it out. A small change in your friends array will get you better result with minimal coding. Use angular to minimalize your coding.

    <!DOCTYPE html>
<html ng-app="plunker">

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <script data-require="angular.js@1.4.x" src="https://code.angularjs.org/1.4.2/angular.js" data-semver="1.4.2"></script>
    <script src="app.js"></script>
  </head>

  <body ng-controller="MainCtrl">
    <ul>
      <li ng-repeat="friend in friends | filter:{name:currentUser}">
        {{ friend.name }}
      </li>
    </ul>
  </body>

</html>

app.js

app.controller('MainCtrl', function($scope) {
  $scope.currentUser = 'Mark';
  $scope.friends = [{'name':'Andrew'}, {'name':'Will'}, {'name':'Mark'}, {'name':'Alice'}, {'name':'Todd'}];
});
Alaksandar Jesus Gene
  • 6,523
  • 12
  • 52
  • 83
0

Try below updated filter. You are returning String whereas you should return an array. Thats why ng-repeat is considering that String as an array and iterating every letters.

app.filter('myFriend', function () {
    return function (items, currentUser) {
        console.log(items);
        console.log(currentUser);
        var finalItems = [];
        for (var i = 0; i < items.length; i++) {
            if (items[i] === currentUser) {
                finalItems.push(items[i]);
            }
        }
        return finalItems;
    };
});
Nitesh Mishra
  • 311
  • 1
  • 10