2

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.. Any ideas to get this to work?

1
  • Ok, now it's working. I was missing the curly braces on the ui-sref=post({filter: 'training'}) Commented Dec 28, 2018 at 5:27

2 Answers 2

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.

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

3 Comments

The tags are dynamic (and I can't tell how many tags there maybe after deploying the application because the tags will be added when creating a new post). So basically one may choose a tag from existing tags or add a new one if it's not in the list of existing tags. Got it?
Umm, I am not sure if I got it exactly. Can't the url be formed dynamically? Let's say the URL is now 'posts?filter=angularjs' and a user clicks on another tag 'training', then get the current URL and append 'training' to it. I hope this is doable in angularjs.
This might be a great use-case... How can I implement this in angularjs, because currently I can only filter with a single tag (another tag does not get appended to the current one)
0

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.

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.