views:

65

answers:

4

Sorry if the title doesn't accurately describe what I'm trying to do. I'm a novice at all this to say the least! To help you understand what I'm trying to accomplish please read the example below.

I have a list of divs, each of which may have a series of "tags" as I'll call them. For this example I'll use Red, Blue, and Green as the possible tags. Each tag also has a button linked to it, which the user can click to filter what divs are displayed. When the button is "on" it will display divs with that specific tag, but when it's "off" it will hide content with that tag. That is unless content has another tag that's currently turned on.

Red: ON

Blue: OFF

Green: ON


DIV 1: Red

DIV 2: Blue

DIV 3: Green

DIV 4: Red, Blue

DIV 5: Blue, Green

DIV 6: Green, Red

Because the tag Blue is turned off every DIV will be displayed except DIV 2. The reason it still displays DIV 4 and DIV 5 is because the tags Red and Green are still turned on. If you were to turn off the tag Red as well only DIVs 3, 5 and 6 would be displayed, since only Green is turned on.

I'm sure there's a much more elegant way of explaining the above but hopefully it got the point across. I've been searching for a solution that would achieve this, but have yet to find it. There are a lot of list filters that use search boxes but that wouldn't work for my needs.

If someone could point me in the right direction as to what I could use to accomplish this I'd appreciate it!

A: 

I think the easiest way to do that is for your "tags" to be directly implemented as classes. Any div can have multiple classes, so class="red blue" is no problem.

Then you just need some javascript to change the class' display to 'none' if appropriate.

Look at javascript's getElementsByClassName() function or jQuery's class selector to get all the divs with a class equal to whatever just changed, and iterate over them and compute the new value of each "display" style attribute.

Scott Stafford
Using classes is what I tried at first, though admittedly I just used CSS with no Javascript (this was done as a sort of Proof of Concept). The issue I ran into is that if Blue was off and Green was on, "Blue Green" was turned off. If we use the example above only DIVs 1, 3 and 6 would display because they did not have Blue as a tag. I guess that's just how CSS handles it.I looked into getElementsByClassName and it's about to drive me crazy :) document.getElementById() works, but document.getElementsByClassName() doesn't. CONT...
Edvard D
... I'm using the code for .getElementsByClassName provided here: http://robertnyman.com/2008/05/27/the-ultimate-getelementsbyclassname-anno-2008/ If I use document.getElementsByClassName("Red").style.display = "none"; with the above code pulling the ClassName for me shouldn't it work? This is just piece one of a thousand piece puzzle for me.
Edvard D
@Edvard D: I'm not actually much of a javascript expert, but I think you have to iterate over the return from getElementsByClassName rather than just try to .style.display the returned array. (Please correct me if I'm wrong).
Scott Stafford
A: 

So what you have here is a logic OR:

If red OR blue OR green is not turned off, show the div.

Hence, this means that as you loop through the divs, you need to have an inner loop for each tag, which inner loop can break whenever you stumble onto a tag that is not turned off, which means the div is shown. Otherwise, if you found no tag which are not turned off after going through all tags, you have to hide the div.

R. Hill
If I understand you correctly the JavaScript function should be separated into as many sections as I have tags, so in the example above, three. Each of those should have a loop within them to go through all the possible combinations, for example the Red tag (red, red blue, blue red, red green, green red). For every tag I add I would need to add another possibility to the other tags, so if the new tag Yellow was added I would need two new combinations (red yellow, yellow red). Is this correct or did I completely miss what you were explaining?
Edvard D
I had in mind your tags are collected in a single object {} (i.e. tags['Blue'] - true/false). Whenever a tag is toggled on or off, you call a function which iterate through the divs, and for each div, you call a function which return true/false depending on whether there is at least a single tag not turned off within it. So say if you have "<span class='tag'>tag name,</span>" objects within your div, this inner function would call div.querySelectorAll('.tag') and the inner text node of each returned element used as a lookup into the tag collection to find out their individual state.
R. Hill
A: 

I don't think this can be solved with CSS alone since you have some DIVs with multiple colors. You could possibly simulate that in CSS, but it probably would not be very elegant. I haven't worked with JavaScript in a long time or much at all, so the solution may need some tidying up or syntax may need to be checked, but I think I have a potential frame you could work with.

You set your three color buttons up, and have onClick (or jQuery equivalent) to a function.

<input type="button" id="buttonRed" name="buttonRed" onclick="theSwitch('red')" />
<input type="button" id="buttonGreen" name="buttonGreen" onclick="theSwitch('green')" />
<input type="button" id="buttonBlue" name="buttonBlue" onclick="theSwitch('blue')" />

Then for the DIVs, you can put them inside a loop (there may be a better solution ... like maybe make the function make the loop go through again so it's not always running).

Here's the function. Before the buttons, of course.

function theSwitch(color) {
    if (color === 'red') {
        var redStatus = 0;
        return redStatus;
    }
}

Theoretically (since I'm not testing this), we change a variable to zero because we want to compare values for the divs that have multiple colors. This is how you could check the two colors, I believe:

if (redStatus === 0 && greenStatus === 0) {
    document.getElementById("divRedGreen").style.display = "none";
}

As you can see here, it requires BOTH buttons to be pressed before it is hidden, which is your desired effect.

You can do many, many variations depending what you are trying to do or whatever is most organized, but I think this could helpful as a loose base.

Tarik
+1  A: 

Here is a working example on how you could do this :

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"&gt;
<html> 
  <head> 
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" >

    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"&gt;&lt;/script&gt; 
   <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.2/jquery-ui.min.js"&gt;&lt;/script&gt; 

   <script type="text/javascript"> 
   //<!--
      $(document).ready(function() {
         var buttons = {
            'red': $('<input type="button"></input>').val('RED: on'),
            'green': $('<input type="button"></input>').val('GREEN: on'),
            'blue': $('<input type="button"></input>').val('BLUE: on')
         };
         var tags = [];
         var _updateTaggedElements = function() {
            // somewhat optimized if...then...else
            if (0 == tags.length) {
               $('#taggedElements > .red,.green,.blue').hide();
            } else {
               $('#taggedElements')
                  .find('.' + tags.join(',.')).show().end()
                  .find(':not(.' + tags.join(',.') + ")").hide()
               ;
            }
         };

         $.each(buttons, function(c,el) {
            tags.push(c); // all tagged elements initially visible...
            $('#buttons').append(el.click(function() {
               var state = /off$/.test(el.val());
               var tagIndex = $.inArray(c, tags);
               el.val(c.toUpperCase() + ": " + (state ? 'on' : 'off'));

               if (state) {
                  if (-1 == tagIndex) {
                     tags.push(c);
                  }
               } else if (-1 != tagIndex) {
                  tags.splice(tagIndex, 1);
               }

               _updateTaggedElements();
            }));
         });

      });
   //-->
   </script>    
   <title>Button selector test</title>
</head> 
<body> 
   <div id="buttons"></div>

   <div id="taggedElements">
      <div class="red">DIV 1: Red</div>
      <div class="blue">DIV 2: Blue</div>
      <div class="green">DIV 3: Green</div>
      <div class="red blue">DIV 4: Red, Blue</div>
      <div class="blue green">DIV 5: Blue, Green</div>
      <div class="green red">DIV 6: Green, Red</div>
   </div>

</body> 
</html>

Of course, modify this for your needs, but as you see, it's fairly easy and small to implemnt. Using the tags array, you may have as many combination of tags as you want.

Yanick Rochon