Home > Enterprise >  Alpine.js filter content by tags
Alpine.js filter content by tags

Time:06-30

I'm trying to wrap my head around filtering content by tags, but I can't find any good solution for my use case. Or I'm trying to do it the wrong way.

What I'm trying to do is simply show or hide content based on what tags the user selects to filter by. All the content is pre-generated and visible to the user, and all they can do is only narrow the content down by the filter.

I'm new to Alpine.js so I don't know if this can be done in a better way. This code works, and all I do is just set the item visibility to true, unless a tag the item doesn't belong to is active. But this feels like a complete overhead (especially if there are multiple tags to chose from).

    <button x-data="{active:false}" @click="$dispatch('tag1'), active=!active" :> Tag1</button>
    <button x-data="{active:false}" @click="$dispatch('tag2'), active=!active" :> Tag2</button>
    <button x-data="{active:false}" @click="$dispatch('tag3'), active=!active" :> Tag3</button>
    <button x-data="{active:false}" @click="$dispatch('tag4'), active=!active" :> Tag4</button>

    <div x-data="{tag1: false, tag2: false, tag3: false, tag4: false}" @tag1.window="tag1=!tag1" @tag2.window="tag2=!tag2" @tag3.window="tag3=!tag3" @tag4.window="tag4=!tag4" >
        <div x-show="true && (!tag3 && !tag4)">
            Show if tag1 and/or tag2 is true. Hide if Tag3 and/or Tag4 is true
        </div>
        <div x-show="true && (!tag1 && !tag3)">
            Show if tag2 and/or tag4 is true. Hide if Tag1 and/or Tag3 is true
        </div>
    </div>

I'm using Laravel as the backend (still new to that), the reason I'm trying to filter things this way is to reduce the number of DB queries and to make it look smoother than refreshing the page every time.

I also tried looking into jQuery but only examples I could find were filtering by element id or class. This is the closest I found to what I need. Is it possible to filter by a different attribute like for example x-data, that would contain a list of tags the content belongs to?

EDIT: Based on @Dauros answer, here is an updated version of how I did it in the end, in case someone will need it. The logic is turned around to always display the content, unless a tag under which the content doesn't belong is selected. The is_selected function is updated to accept a list of tags the content needs to be hidden from !is_selected('[tag3,tag4]') .This way the need of function calls from the item is reduced to only one.

<script src="https://unpkg.com/[email protected]/dist/cdn.min.js"></script>

  <div 
    x-data="{
      tags: [],
      toggle(tag) {
        if (this.tags.includes(tag)) {
          this.tags = this.tags.filter(x => x != tag)
        }
        else {
          this.tags.push(tag)
        }
        },
        is_selected(tag) {
          return this.tags.some(r=> tag.indexOf(r) >= 0)
        }
     }">

    <button @click="toggle('tag1')" :style="is_selected('tag1') && {background: 'salmon'}">Tag 1</button>
    <button @click="toggle('tag2')" :style="is_selected('tag2') && {background: 'salmon'}">Tag 2</button>
    <button @click="toggle('tag3')" :style="is_selected('tag3') && {background: 'salmon'}">Tag 3</button>
    <button @click="toggle('tag4')" :style="is_selected('tag4') && {background: 'salmon'}">Tag 4</button>

    <div x-show="true && !is_selected('[tag3,tag4]')">
      Show if tag1 and/or tag2 is true. Hide if Tag3 and/or Tag4 is true
    </div>
    <div x-show="true && !is_selected('[tag1,tag3]')">
      Show if tag2 and/or tag4 is true. Hide if Tag1 and/or Tag3 is true
    </div>
</div>

CodePudding user response:

Instead of creating a new variable for each tag, you can use a list and create toggle(tag) and is_selected(tag) functions for toggling and checking their state. The show/hide logic is still kinda complicated but you can generate it on the backend as well.

<script src="https://unpkg.com/[email protected]/dist/cdn.min.js"></script>

<div x-data="{
  tags: [],
  toggle(tag) {
    if (this.tags.includes(tag)) {
      this.tags = this.tags.filter(x => x != tag)
    }
    else {
      this.tags.push(tag)
    }
  },
  is_selected(tag) {
    return this.tags.includes(tag)
  }
}">

  <div>
    <button @click="toggle('tag1')" :style="is_selected('tag1') && {background: 'salmon'}">Tag 1</button>
    <button @click="toggle('tag2')" :style="is_selected('tag2') && {background: 'salmon'}">Tag 2</button>
    <button @click="toggle('tag3')" :style="is_selected('tag3') && {background: 'salmon'}">Tag 3</button>
    <button @click="toggle('tag4')" :style="is_selected('tag4') && {background: 'salmon'}">Tag 4</button>
  </div>
  <br>
  
  <div x-show="(is_selected('tag1') || is_selected('tag1')) && !(is_selected('tag3') || is_selected('tag4'))">
      Show if tag1 and/or tag2 is true. Hide if Tag3 and/or Tag4 is true
  </div>
  <div x-show="(is_selected('tag2') || is_selected('tag4')) && !(is_selected('tag1') || is_selected('tag3'))">
      Show if tag2 and/or tag4 is true. Hide if Tag1 and/or Tag3 is true
  </div>
  <br>
  
  <div x-text="`Selected tags: ${tags}`"></div>
</div>

  • Related