0

My best attempts at finding a solution to this have come up empty. Basically I want to do something like this in my html:

    <div data-ng-repeat="tag in allTags">
  <h3>{{tag}}</h3>
  <uib-accordion>
    <div uib-accordion-group data-ng-repeat="item in displayItems | filter: tagFilter: tag">

tagFilter looks like this:

  $scope.tagFilter = function(item, tag) {
    if(item.tags.indexOf(tag) === -1) {
      return false;
    }
    return true;
  }

Each item in displayItems is an object that has an array of tags, so display items looks something like this:

[
{ title: "Item 1 Title", body: "Some escaped HTML Content", tags: ["tag1", "tag2", "tag3"]}, 
{ title: "Item 2 Title", body: "Some escaped HTML Content", tags: ["tag2", "tag4"] }
]

and I want it to appear under all headings to which it belongs. The problem is I can't figure out how to properly pass the value of 'tag' to tagFilter. In the code above the parameter tag in codeFilter is just equal to 0 no matter what.

3 Answers 3

2

The problem here is actually in the semantics of the Filter syntax. More specifically, the syntax you're using above is for when you're defining an Angular Filter using the ngApp.filter(...) syntax... i.e., a filter that's registered for the entire application and can be used anywhere. In that scenario the 3rd parameter in your filter statement is the value you want to pass to the registered filter.

In your case, you're defining a filter function inside your controller which changes how the filter works. Specifically, you cannot pass dynamic values to a filter function inside a controller. When you use a function as the filter expression, it has the following signature:

function(value, index, array) {}

and then gets called in the filter statement just by the function name, so:

array|filter:filterfunction - with no params or parenthesis.

value is the value of the current item (in the array) being filtered, index is the index of that item in the array, and array is the whole array being filtered. You cannot "pass" a value to this expression, but you can use a controller or scope variable if it applies. In your case it doesn't because the value you want to filter on is inside a repeater.

To achieve what you want, you need to make your $scope.tagFilter into an actual Angular Filter, like so:

ngApp.filter('tagFilter', function($filter)
{
        return function(items, searchValue)
        {   
            // initialize array to return
            var filtered = [];

            angular.forEach(items, function(obj)
            {
               // use filter to find matching tags (3rd param means EXACT search - set to False for wildcard match)
               var objFilter = ($filter("filter")(obj.tags, searchValue, true))[0];

               // If a matching tag was found, add it to the filtered array
               if (objFilter) filtered.push(obj);
            });

            return filtered;
        };
    });

The above assumes you've saved your angular.module(...) bootstrap to a variable named ngApp. Once this filter is registered, your current filter syntax should work as expected!

Sign up to request clarification or add additional context in comments.

3 Comments

unfortunately, it doesn't seem to help, behavior is exactly the same as before
Need to see more of your use-case then. If "displayItems" is an object and not an array, then it won't work - otherwise it should. Can you post what your data points look like? Also might want to try assigning tagFilter and your data points to a controller variable instead of using $scope. Personally I never use $scope variables anymore just because of nuances with ng-if and other directives that can cause $scope assigned variables to not be accessible.
Added an example of what displayItems would look like (it is originally JSON data retrieved from the server). I have checked via dev tools and it is being brought in and interpreted correctly.
0

Assuming displayItems is an array,

<div uib-accordion-group data-ng-repeat="item in displayItems.filter(tagFilter(tag))" >

should do the trick.

1 Comment

This caused the 'item' in my tagFilter function to be passed the value of the tag, and tag to be undefined. I tried instead displayItems.filter(tagFilter(item, tag)) after which tag was correct and item was undefined.
0

Figured out a way to do this based on this blog post: https://toddmotto.com/everything-about-custom-filters-in-angular-js/

Basically I had to create my own custom filter rather than using angulars predicate filter

The Javascript:

  ng.module('faq').filter(
    'tagFilter', function() {
      return function(items, tag) {
        return items.filter(function(item) {
          if(item.tags.indexOf(tag) === -1) {
            return false;
          }
          return true;
        });
      }
    }
  )

The HTML:

<div uib-accordion-group data-ng-repeat="item in displayItems | tagFilter: tag">

Still don't know why the original version was not working, so if anyone can answer that 10 points to them.

Comments

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.