How to use (multiple) tags as filter for displaying resources dynamically?

I’m looking for a way to dynamically list resources depending on the selection of one or multiple tags assigned to them with tagger. I would like it to be automatic, meaning without the need to press an “Apply Filter” button or similar. Basically a pdoResources call on a page with a dynamic &where property depending on the selection, is what I need.

I’ve already looked through a lot of older threads and other posts, but couldn’t find a fitting solution to my case. I found the extra mSearch2 which looks like it’s doing what I need, but I’m a little hesistant due to the translated docs and as I don’t need an actual Search field, this might be more than I need.

Thanks for any ideas!

I don’t exactly understand what you are trying to do, but I think the extra Tagger is all you need.
The snippet TaggerGetResourcesWhere reads the values from the $_GET parameters.

https://mydomain.com/mypage?my_group1=my_tag1,my_tag2&my_group2=my_tag3

To make it “dynamic”, you have to append the parameters in the frontend with Javascript and then reload the page or make an AJAX-request.

I probably didn’t make that clear enough, but I’m using checkboxes to select the tags. Still a very good hint about the $_GET parameter usage with Tagger though, that’s a good way of doing it.

I’m currently stuck on the script generating the URL. I thought that location.hash would be a good method, but I can’t get rid of the #. Here’s what I have so far, which gives me almost what I need:

  $checkboxes = $('input[type=checkbox]');
        
  $checkboxes.change(function(){
    var hash = $checkboxes.filter(':checked').map(function(){
      return this.value;
    }).toArray().join(",");
          
    location.hash = '?filter=' + hash;
  });
  
  // select checkboxes on reload

  if (location.hash !== "") {
    var hash = location.hash.substr(9).split(",");
    hash.forEach(function(value) {
      $("input[value=" + value + "]").prop("checked", true);
    });
  }

Result:

https://mydomain.com/mypage # ?filter=my_tag1,my_tag2,my_tag3

Maybe this would work

location.hash.replace(/^#/, '')

From this deep dive into removing the pound sign:

Maybe use location.search (or location.href ) instead of location.hash.

By the way, if you use friendly urls, you can also use this form to create your url with the tags:

https://mydomain.com/mypage/my_group1/my_tag1/my_tag2/my_group2/my_tag3

Unfortunately it doesn’t, but still a very interesting read, thanks!

That did it! I know that I looked at that before, not sure why it didn’t click for me then…

Now the basic functionality is there, but I would definitely prefer only the resource call to be updated when a checkbox is checked (instead of reloading the whole page like how it’s working atm). I’ve been looking into how to implement an AJAX solution here, but if I understand correctly a regular AJAX call doesn’t work with MODX? I found an old thread with a rough explanation, I don’t really know where to start on this though.

I’m aware that my script would need more adjustments for this functionality, also location.search wouldn’t work as it causes a full refresh if I’m not mistaken. Maybe history.pushState is a good option then?

The simplest solution is to load the same page you already have with the jQuery function get() and then just replace the content of your filter results. Something like:

$.get("https://mydomain.com/mypage?filter=my_tag1,my_tag2", function(data) {
  $('#my_filter_result_container').replaceWith($(data).find('#my_filter_result_container'));
});

That creates some overhead, because you are also loading all the rest of your page that you already have. So you could create a new resource that only serves as an ‘ajax endpoint’, where you have a blank template and only a call to pdoResources to just return the html of the filter results and not a whole webpage.

$.get("https://mydomain.com/my_ajax_endpoint?filter=my_tag1,my_tag2", function(data) {
  $('#my_filter_result_container').html(data);
});

I tried setting this up, but I don’t get anything from the pdoResources call (I do get the surrounding divs). It’s also a pdoPage call but I guess that shouldn’t make a difference?

The “main” resource:

// checkboxes

// <div id="container"></div>

$checkboxes = $('input[type=checkbox');
        
$checkboxes.change(function(){
  var tag = $checkboxes.filter(':checked').map(function(){
    return this.value;
  }).toArray().join(",");
          
  $url = '[[++site_url]][[~87]]' + '?filter=' + tag;
          
  $.get($url, function(data) {
    $('#container').html(data);
  });
});

Template of the AJAX endpoint resource (id 87):

<div id="pdopage" class="inner">
  <div class="posts rows">  
  [[!pdoPage?
    &parents=`6`
    &where=`[[!TaggerGetResourcesWhere?
      &matchAll=`1`]]`
    &sortby=`{"pagetitle":"ASC"}`
    &tpl=`tpl-name`
    &includeTVs=`tv-name`
    &tplPageWrapper=`@INLINE <div class="pagination"><ul class="pagination">[[+first]][[+prev]][[+pages]][[+next]][[+last]]</ul></div>`
      &ajaxMode=`default`
    ]]
  </div>
  
  [[!+page.nav]]
	
</div>

I probably missed something?

It seems to work if I delete this property:

&ajaxMode=`default`

Your AJAX-request conflicts with the built-in mechanism for the AJAX-paging. When there is no page parameter the snippet just returns.

Is there a way to keep the pagination, though?

I’m not familiar with pdoPage but looking at the documentation, there seems to be a lot of possibilities.
The section Example call with form filtering seems promising and if that doesn’t work, then maybe this section where you have to program more yourself though.