Angularjs custom filters (Filtering an array of objects )

问题: I am making a Web App using angularjs. I have a list of posts that are fetched from the backend in the following structure: [ { post: { postID: 1, title...

问题:

I am making a Web App using angularjs. I have a list of posts that are fetched from the backend in the following structure:

[
  {
    post: {
      postID: 1,
      title: "sample title", 
      body: "so many paragraphs here", 
      post_date: "2018-12-26 02:21:35"
    } 
    tags: [
      {
        tagTitle: "training"
      }, 
      {
        tagTitle: "another tag" 
      } 
    ] 
  } 
]

I want to filter these posts according to the tag that I have clicked on. Say I have clicked on training, I want to display posts that have the training entry in their tags's array.

Since it's an angularjs Web App, the ui-sref is posts(filter: 'training') and the path (url) will be posts?filter=training.

I have created a filter with the following code:

function postsFilter() {
  return function (collection, params) {
    return collection.filter(function (item) {
      var i, tagsArray = item.tags, len = tagsArray.length;
      for (i = 0; i < len; ++i) {
        return tagsArray[i].tagTitle === (
          params.filter === "none" ? tagsArray[i].tagTitle : 
            params.filter;) 
        } 
    });
  };
}

angular.module('app').filter('postsFilter', postsFilter);

In the controller, I have the following code;

function PostsController($filter) {
  angular.extend(this, {
    $onInit: () => {
      this.filteredPosts = $filter('postsFilter')(this.posts, this.filter);
    } 
  } 
}

In the component I have the following code:

const posts = {
  bindings: {
    posts: '<', 
    filter: '<' 
  }, 
  templateUrl: 'path/to/my/posts.html',
  controller: 'postsController'
};

angular.module('app').component('posts', posts).config(
[
  '$stateProvider', function ($stateProvider) {
    $stateProvider.state (
      'posts', {
        url: '/posts?filter',
        component: 'posts', 
        params: {
          filter: {
            value: 'none'
          }
        }, 
        resolve: {
          posts: ['PostsService', function (PostsService) {
            return PostsService.getPostList();
        }],
        filter: ['$transition$', function ($transition$) {
          return $transition$.params();
        }]
      } 
    }
  );
  } 
]);

In the posts.html I then want display the filtered posts like:

<div ng-repeat='post in $ctrl.filteredPosts'>
  {{post.post.title}}
</div>

With my current code, when I click on a link to filter the posts (say ui-sref='posts({filter: 'angularjs'})), the posts don't get filtered. The url changes but the posts still display all of them. By default, url to posts shows /posts?filter=none. When I click on a link to filter the posts (say the tag is angularjs), the url changes to /posts?filter=angularjs.

How should I make this correct?

OK, now it is working after putting those missing curly braces. The problem I now have is that, if a post has two or more tags, I can't filter it with the other tags, it only works with the first tag.

In this example, it will only be filtered with training, it doesn't get filtered with another tag.. In ideas to get this to work?


回答1:

if a post has two or more tags, I can't filter it with the other tags, it only works with the first tag

You can try forming the URl like this

posts?filter=angularjs&training

And then in the filter function, form an array of filter tags. Thus you will have two arrays - Collection and Filters. Now use javascript Array Includes function for each of the filter in Filters Array. Something like below (you would need to tweak it according to your model structure):

let filteredCollection = new Array();
filters.foreach((filter) => {
  if(collection.includes(filter)) {filteredCollection.push(collection)}
})

Although this includes parsing through two arrays everytime, but it is the quickest solution at hand.


回答2:

I have solved the problem myself. I changed the filter code to the following (and it's working perfectly now).

function postsFilter () {
return function (collection, params) {
return collection.filter(function (item) {
var i, tagArray = item.tags, len = tagArray.length;
for (i = 0; i < len; ++i) {
if (params.filter === tagArray[i].tagTitle) {
return tagArray[i].tagTitle === (
params.filter === 'none' ? tagArray[i].tagTitle : params.filter
);
} else if (params.filter === 'none') {
return tagArray[i].tagTitle === (
params.filter === 'none' ? tagArray[i].tagTitle : params.filter
);
} 
} 
}
} 
}

This makes what I wanted to happen but I don't like the kind of hack I've made. I've repeated the code. If someone can help make it DRY, that would be great.

  • 发表于 2018-12-28 14:40
  • 阅读 ( 186 )
  • 分类:网络文章

条评论

请先 登录 后评论
不写代码的码农
小编

篇文章

作家榜 »

  1. 小编 文章
返回顶部
部分文章转自于网络,若有侵权请联系我们删除