0

Is there a better way to write something like this. I have a couple Divs that have lists in them that I want to display based on the selection in a drop down. for the sake of not having to update each block to hide then show the one I want is there a wild card approach or way I can simply use an array defining my Divs to loop through for hide/display?

basis of what I was building. Planned on converting to a switch statement instead of a series of If statements.

I am not liking this portion primarily.

document.getElementById('my1').style.display = 'block';
document.getElementById('my2').style.display = 'none';
document.getElementById('my3').style.display = 'none';

http://jsfiddle.net/ak95K/3/

ATek
  • 815
  • 2
  • 8
  • 20
  • 1
    Get elements by *class* ([see this answer](http://stackoverflow.com/a/15396712/870729)), not by *ID*, then you can just have two javascript calls. Assign the appropriate class(es) to the element(s), and you can "collectively" show / hide them. – random_user_name Apr 21 '14 at 21:34
  • I don't like that portion too because no one write codes like that :) – Derek 朕會功夫 Apr 21 '14 at 21:35
  • use jQuery, to show an element you simply use $("#my1").show() and $("#my1").hide() to hide ! it's really easy and only involves linking to the Jquery extarnal JS File – numX Apr 21 '14 at 21:39
  • @cale_b Thanks will give that a try. some of the syntax in it I am not familiar with but I think I can figure it out. – ATek Apr 21 '14 at 21:40

3 Answers3

1

You can use CSS to control what to display: http://jsfiddle.net/DerekL/ak95K/5/

There are many ways to do it. This is the one I prefer the most:

document.querySelector("select").addEventListener("change", function(){
    var c = document.querySelector("#display");
    c.className = "";
    c.classList.add(this.value);
});

.my1 > :not(#my1){
    display: none;
}
.my2 > :not(#my2){
    display: none;
}

PS: classList is not supported by IE 9 or earlier. However for this case you can just do c.className = "this.value". Or just go for jQuery 'cause it solves every problem in the Universe.

Derek 朕會功夫
  • 92,235
  • 44
  • 185
  • 247
  • Using a `class` would be the route that I would initially take, but worth noting that the `classList API` is a recent development and not available on older browsers. – Xotic750 Apr 21 '14 at 21:42
  • Tossing my jQuery based answer. Good edit to querySelector "#display" just once. – Stephen P Apr 21 '14 at 21:44
  • working in corporate environment, IE subset of v8-10. – ATek Apr 21 '14 at 21:45
  • Without the need to load `jQuery` just for handling `classList` in environments that don't support it, take a look at http://stackoverflow.com/questions/195951/change-an-elements-css-class-with-javascript/196038#196038 – Xotic750 Apr 21 '14 at 22:00
  • I was able to get this going and it works great. Except for the environment the user set is in. looks like our term servers where I suspect a good handful of users would access the site will end up running IE8 Compat view Document mode as IE7. Picked up as local intranet and forced down in GPO. – ATek Apr 22 '14 at 06:31
1

If I needed to support older (but not ancient) browsers (and wasn't using jQuery), like you are saying, then I would do something like this.

CSS

.hide {
    display: none;
}

HTML

<select id="mine">
    <option value="0">Test1</option>
    <option value="1">Test2</option>
</select>
<div id="display1">
    <div>
        <p>Some Text in 1</p>
    </div>
    <div class="hide">
        <p>Some Text in 2</p>
    </div>
</div>

Javascript Cross Browser Support Code

(function () {
    var slice = [].slice,
        nativeTrim = ''.trim,
        trim,
        classList;

    function isFunction(arg) {
        return typeof arg === 'function';
    }

    function isString(arg) {
        return typeof arg === 'string';
    }

    function handler(object, evt, func) {
        var ret;

        if (evt) {
            ret = func.call(object, evt);
            if (false === ret) {
                evt.stopPropagation();
                evt.preventDefault();
            }
        } else {
            window.event.target = window.event.srcElement;
            ret = func.call(object, window.event);
            if (false === ret) {
                window.event.returnValue = false;
                window.event.cancelBubble = true;
            }
        }

        return ret;
    }

    function addEventListener(object, type, func) {
        var uid = type + ':' + func,
            euid = 'e:' + uid;

        object[euid] = func;
        if (isFunction(object.addEventListener)) {
            object[uid] = function (evt) {
                handler(object, evt, object[euid]);
            };

            object.addEventListener(type, object[uid], false);
        } else if (object.attachEvent) {
            object[uid] = function () {
                handler(object, null, object[euid]);
            };

            object.attachEvent('on' + type, object[uid]);
        } else {
            throw new Error('Handler could not be added.');
        }
    }

    if (isFunction(nativeTrim)) {
        trim = function (text) {
            return nativeTrim.call(text);
        };
    } else {
        trim = function (text) {
            return text.replace(/^\s+|\s+$/g, '');
        };
    }

    if ('classList' in document.body) {
        classList = {
            contains: function (node, className) {
                return node.classList.contains(className);
            },

            add: function add(node, className) {
                node.classList.add(className);
            },

            remove: function (node, className) {
                node.classList.remove(className);
            },

            toggle: function (node, className) {
                node.classList.toggle(className);
            }
        };
    } else {
        classList = {
            makeRegex: function (className, flags) {
                return new RegExp('(?:^|\\s)' + className + '(?!\\S)', isString(flags) ? flags : '');
            },

            contains: function (node, className) {
                return !!node.className.match(classList.makeRegex(className));
            },

            add: function add(node, className) {
                if (!classList.contains(node, className)) {
                    node.className = trim(node.className);
                    if (node.className) {
                        node.className += ' ';
                    }

                    node.className += className;
                }
            },

            remove: function (node, className) {
                if (classList.contains(node, className)) {
                    node.className = trim(node.className.replace(classList.makeRegex(className, 'g'), ''));
                }
            },

            toggle: function (node, className) {
                if (classList.contains(node, className)) {
                    classList.remove(node, className);
                } else {
                    classList.add(node, className);
                }
            }
        };
    }

    window.$ = {
        addEventListener: addEventListener,
        classList: classList
    };
}());

Javascript Working Code

$.addEventListener(document.getElementById('mine'), 'change', (function () {
    var children1 = document.getElementById('display1').children,
        length1,
        index;

    return function (evt) {
        for (index = 0, length1 = children1.length; index < length1; index += 1) {
            $.classList.toggle(children1[index], 'hide');
        }
    };
}()));

On jsFiddle

Update: Adding options

CSS

<select id="mine">
    <option value="test1">Test1</option>
    <option value="test2">Test2</option>
    <option value="test3">Test3</option>
</select>
<div id="display1">
    <div>
        <p>Some Text in 1</p>
    </div>
    <div class="hide">
        <p>Some Text in 2</p>
    </div>
    <div class="hide">
        <p>Some Text in 3</p>
    </div>
</div>

Javascript

$.addEventListener(document.getElementById('mine'), 'change', (function () {
    var children1 = document.getElementById('display1').children,
        length1,
        index;

    return function (evt) {
        for (index = 0, length1 = children1.length; index < length1; index += 1) {
            if (index === evt.target.selectedIndex) {
                $.classList.remove(children1[index], 'hide');
            } else {
                $.classList.add(children1[index], 'hide');
            }
        }
    };
}()));

On jsFiddle

If you were writing without the need to support older browsers, then it would look like this.

Javascript

document.getElementById('mine').addEventListener('change', (function () {
    var children1 = document.getElementById('display1').children,
        length1,
        index;

    return function (evt) {
        for (index = 0, length1 = children1.length; index < length1; index += 1) {
            if (index === evt.target.selectedIndex) {
                children1[index].classList.remove('hide');
            } else {
                children1[index].classList.add('hide');
            }
        }
    };
}()), false);

On jsFiddle

Xotic750
  • 22,914
  • 8
  • 57
  • 79
  • I am not sure I understand what is going on here. Looks like you are assigning an index value to each select option and then organizing all first level tags in the `#display1` div to coincide with the select list via a zero based array? I tried to add another option entry to the beginning as a test `` then throwing an empty div just inside the `#display` div. Am I thinking about it wrong? – ATek Apr 22 '14 at 06:48
  • The option values are irrelevant to the operation, they could just have remained `test1` and `test2`, I changed them to numbers so that you understood that they are the `index` numbers of `children1` of `div` with the id `display`. I used `toggle` because there were only 2 options, if you add more then `toggle` would no longer work be appropriate. If you are adding more then see my update, hopefully that helps you understand a little more. – Xotic750 Apr 22 '14 at 08:21
  • yep understand more now on the structure. Works great for the most part but IE8 doesn't like this function. `function addEventListener(object, type, func)` ends up tossing a handler could not be added exception. Any thoughts? Thanks in advance for your help, really appreciate it. – ATek Apr 24 '14 at 04:06
  • I don't have IE to test with but I guess that `object.attachEvent` is reporting itself as an `object` rather than a `function`, so just change the line `} else if (isFunction(object.attachEvent)) {` to `} else if (object.attachEvent) {` and it should begin to work. – Xotic750 Apr 24 '14 at 08:30
  • making that change still worked in IE10 but in IE8 it now throws an object expected error on this line. `return new RegExp('(?:^|\\s)' + className + '(?!\\S)', isString(flags) ? flags : '');` – ATek Apr 24 '14 at 16:09
  • I missed the `isString` function, I will add it to the answer. – Xotic750 Apr 24 '14 at 17:20
  • Works with those two changes. Thanks so much! I don't understand some of the functions but have lots more to do so I will come full circle and try to grasp it. One thing it looks like I might have to do unless you have some thoughts is since I am using in a form when I submit my php file and request the values to validate and then in some cases refill field values that were previously submit the default hide class is on the wrong div so I will probably throw a php if or case block in to handle it. Thanks again for taking the time. – ATek Apr 25 '14 at 08:12
  • Glad that it is working for you now. In the design I did not consider that the dropdown may begin at a dynamic position, and created it as a static. Creating it to be dynamic using Javascript would not be that difficult though (or PHP if that is your preferred way). Good luck. – Xotic750 Apr 25 '14 at 10:07
0

HTML

Make your divs part of a particular class (.my).

<select name="mine" id="mine">
    <option value="#my1">Test1</option>
    <option value="#my2">Test2</option>
</select>

<div id="my1" class="my">
    <p>Some Text in 1</p>
</div>

<div id="my2" class="my">
    <p>Some Text in 2</p>
</div>

CSS

Only show that class when it is accompanied by another class (.selected).

.my:not(.selected) {
    display: none;
}

JavaScript

Add and remove that class (.selected) appropriately.

document
    .querySelector('select')
    .addEventListener('change', function () {
        var elements = Array.prototype.slice.call(document.querySelectorAll('.my'), 0),
            target = document.querySelector(this.value);

        elements
            .forEach(function (elem) {
                if (elem === target) {
                    elem.classList.add('selected');
                } else {
                    elem.classList.remove('selected');
                }
            });
    });

You could also deforest the whole thing by tracking the previously selected element and only remove the .selected class from the previous element, instead of all of them.

http://jsfiddle.net/ak95K/7/

cwharris
  • 17,835
  • 4
  • 44
  • 64
  • two questions on this. Why the Hash sign for the value on the select now? Second, how would you define a default selection and and display of one of the divs's? – ATek Apr 21 '14 at 22:31
  • Hash is just a pre-fixed used to denote title. so '#hey' would match the element with an `id` of "title". In our case, the select values are ids of elements. For a default selection, just add the `.selected` class to the "default" element in the HTML. – cwharris Apr 21 '14 at 23:04