简体   繁体   中英

Filter an ng-repeat based on parent ng-repeat

Scratching my head now for 2 hours. Maybe I'm tired or maybe I don't understand what I'm doing. Anyway, I've got an array of blogposts. Which looks like this:

[
  {
    'title': 'first post', 
    'tags': [
      { 'name': 'Tag 1', 'slug': 'tag-1' }
    ]
  },
  {
    'title': 'second post', 
    'tags': [
      { 'name': 'Tag 1', 'slug': 'tag-1' },
      { 'name': 'Tag 3', 'slug': 'tag-3' }
    ]
  },
  {
    'title': 'third post', 
    'tags': [
      { 'name': 'Tag 2', 'slug': 'tag-2' }
    ]
  }
]

And also an array containing my tags like this.

[
  {'title': 'Tag 1', 'slug':'tag-1'},
  {'title': 'Tag 2', 'slug':'tag-2'},
  {'title': 'Tag 3', 'slug':'tag-3'},
  {'title': 'Tag 4', 'slug':'tag-4'}
]

And I am doing an regular angular ng-repeat like this to show all my blogpost tags:

<ul>
    <li ng-repeat="tag in blog.tags">
        <h3>{{ tag.title }}</h3>
    </li>
</ul>

Now, I would like to add a nested repeater which only shows blogposts from the variable blog.posts that contains the current tag. Something like this:

<ul ng-controller="BlogComponent as blog">
  <li ng-repeat="tag in blog.tags">
    <h3>{{ tag.title }}</h3>
    <ul>
      <li ng-repeat="post in blog.posts | filter: tag.slug IN post.tags">
        <span>{{ post.title }}</span>
      </li>
    </ul>
  </li>
</ul>

But I cannot seem to get it working. I think it SHOULD be easy. Because in my mind it is a quite simple task. to filter out unwanted results based on a string and an array.

Wanted/Exptected output:

<ul>
  <li>
    <h3>Tag 1</h3>
    <ul>
      <li>first post</li>
      <li>second post</li>
    </ul>
  </li>
  <li>
    <h3>Tag 2</h3>
    <ul>
      <li>third post</li>
    </ul>
  </li>
  <li>
    <h3>Tag 3</h3>
    <ul>
      <li>second post</li>
    </ul>
  </li>
</ul>

You could make a custom filter instead of using "filter: expression". What you can do create a filter that takes the tags and posts as arguments and returns the array with filtered items.

myApp.filter('myFilter', function () {
    return function (posts, tag) {
        var newPosts = [];
          for (var i = 0; i < posts.length; i++) 
            for (var j = 0; j < post.tags.length; j++) 
             if (posts[i].tags[j].slug === tag.slug)
                newPosts.push(posts[i]);

        return newPosts;
    }
});

And then

  <li ng-repeat="post in blog.posts | myFilter: tag">
    <span>{{ post.title }}</span>
  </li>

Using the built-in functionality, you can do it like this:

<ul ng-controller="BlogComponent as blog">
  <li ng-repeat="tag in blog.tags">
    <h3>{{ tag.title }}</h3>
    <ul>
      <li ng-repeat="post in blog.posts | filter: {tags: {slug: tag.slug}}">
        <span>{{ post.title }}</span>
      </li>
    </ul>
  </li>
</ul>

See it working here: https://plnkr.co/edit/pQZse1hUnnzyfneIlpMu?p=preview

Documentation for the filter is here: https://docs.angularjs.org/api/ng/filter/filter

Or, if you want Tag 4 to be hidden because it has no matching posts, you could do something like this:

<div ng-controller="BlogComponent as blog">
  <div ng-repeat="tag in blog.tags">
    <div ng-repeat="post in blog.posts | filter: {tags: {slug: tag.slug}}">
      <h3 ng-if="$first">{{ tag.title }}</h3>
      <li>{{ post.title }}</li>
    </div>
  </div>
</div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM