www.webdeveloper.com
Results 1 to 12 of 12

Thread: Looking to "expand" select box options with onclick event

  1. #1
    Join Date
    May 2003
    Location
    Milwaukee
    Posts
    344

    Looking to "expand" select box options with onclick event

    Good afternoon, folks!

    I have a select box with options that are "summarized" with codes so as not to take up too much real estate on the screen. When the user clicks on the select, I want it to expand to show the label definitions of the codes as well.

    So, for instance...the user will initially see this:

    <select id="s1" name="list1" onclick="expandList();">
    <option label="This is long description 1" value="L1">L1</option>
    <option label="This is long description 2" value="L2">L2</option>
    <option label="This is long description 3" value="L3">L3</option>
    </select>

    when they click the select dropdown, I want it to change to something like this:

    <select id="s1" name="list1" onchange="checkOptions();">
    <option value="L1">L1 - This is long description 1</option>
    <option value="L2">L2 - This is long description 2</option>
    <option value="L3">L3 - This is long description 3</option>
    </select>

    then after they make their selection, the list changes back to the shorter first list.

    Hope this makes sense. As always, thanks in advance for any help you can provide!!

    Tom

  2. #2
    Join Date
    Nov 2010
    Posts
    1,084
    maybe this will be a start...
    Code:
    <body>
    
    <select id="s1" name="list1">
    <option value="L1">L1</option>
    <option value="L2">L2</option>
    <option value="L3">L3</option>
    </select>
    <script>
    (function() {
        var opts = {
            "L1": "L1 - This is long description 1",
            "L2": "L2 - This is long description 2",
            "L3": "L3 - This is long description 3",
        };
    
        var thesel = document.getElementById("s1");
    
        thesel.onfocus = function() {
            var cnt = 0;
            for (i in opts) {
                thesel[cnt++].text = opts[i];
            }
        }
    
        thesel.onblur = changeBack;
        thesel.onchange = changeBack;
    
        function changeBack() {
            var cnt = 0;
            for (i in opts) {
                thesel[cnt++].text = i;
            }
            thesel.blur();
        }
    
    })();
    </script>
    
    </body>
    Last edited by xelawho; 08-02-2014 at 02:20 PM.

  3. #3
    Join Date
    Dec 2005
    Location
    FL
    Posts
    7,377

    Lightbulb

    @xelawho

    Your post #2 is pretty neat.

    Since when I use the dropdown elements I usually do something with the associated value.
    I modified your code a bit to access the longer option description
    since normally it would only pass the shorter text.
    I gives the added benefit on not having to create an additional array for the longer descriptions.
    Nice work ... I highlighted changes in red.

    Code:
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8" />
    <title> Wide Dropdowns </title>
    </head>
    <body>
    
    <select id="s1" name="list1">
     <option value="L1">L1</option>
     <option value="L2">L2</option>
     <option value="L3">L3</option>
    </select><br>
    <button id="s1Pick">Show Pick</button>
    
    <script>
    // From: http://www.webdeveloper.com/forum/showthread.php?298997-Looking-to-quot-expand-quot-select-box-options-with-onclick-event (post #2)
    
    (function() {
      var IDS = 's1'; 
        var opts = {
            "L1": "L1 - This is long description 1",
            "L2": "L2 - This is long description 2",
            "L3": "L3 - This is long description 3",
        };
        var thesel = document.getElementById(IDS);
        thesel.onfocus = function() {
            var cnt = 0;
            for (var i in opts) { thesel[cnt++].text = opts[i]; }
        }
        thesel.onblur = changeBack;
        thesel.onchange = changeBack;
    
        function changeBack() {
            var cnt = 0;
            for (var i in opts) { thesel[cnt++].text = i; }
            thesel.blur();
        }
    
    // allows access to both value and option contents
      document.getElementById(IDS+'Pick').onclick = showPick;
      function showPick() {
        var sel = document.getElementById(IDS);
        var str = 'selectedIndex: '+sel.selectedIndex+'\n';
            str += 'value: '+sel.value+'\n';
    //        str += 'text: '+sel.options[sel.selectedIndex].text+'\n';
            str += 'option: '+opts[sel.value];
        alert(str);
      }
    
    
    })();
    </script>
    
    </body>
    </html>
    Current display is simple alert, but could be changed to allow additional actions.

    Would this be the way you would have changed it?

  4. #4
    Join Date
    May 2014
    Posts
    893
    First off, this is NOT something I recommend you even do on a page. If you can't make room for the select's values (within reason) you probably are doing something REALLY screwball with your layout -- that quite possibly has no business on a website.

    BUT, if you insist...

    I'd suggest using the text instead of LABEL -- as the latter is unreliable in IE8 and keeps creeping up with 'regression' issues in FF (like every other release of FF it disappears from the DOM as a value?), and doesn't even exist outside an OPTGROUP in IE7. When you initialize the page you save the text inside the OPTION and swap it for it's value -- I'd do it this way so scripting off people see the full text. TITLE could be used as a safe place to store it from the scripting, since creating the element would be relatively safe (so long as nothing else is trying to use it). In fact, swapping from LABEL can cause issues as some browsers for some screwball reason some browsers will return the LABEL as the innerText instead of the actual text content :/

    I also wouldn't be trapping 'click', I'd be trapping 'focus' and 'blur' -- and like a good little doobie, I wouldn't be using the 'onevent' attributes to do so, since that puts JS someplace it has no blasted business being -- in the markup. Good scripting should hook the markup, NOT the other way around. JMRKER started doing this, but the method could use a bit of tweaking.

    I'd probably also trap 'change' so that it blurs the element, so when they select an option it goes back to the normal 'short' name.

    I would also likely be trapping the SELECT by className, so you can add this functionality to any select on the page by simply adding a class to it like "swapValues"

    So for example, if you had this:

    Code:
    <select id="s1" name="list1" class="hasTitles">
    	<option value="L1">This is long description 1</option>
    	<option value="L2">This is long description 2</option>
    	<option value="L3">This is long description 3</option>
    </select>
    This script could target it, just include it right before </body>

    Code:
    (function(d) {
    
    	// some simple library functions to make life easier
    
    	function classExists(e, className) {
    		return RegExp('(\\s|^)' + className + '(\\s|$)').test(e.className);
    	}
    	
    	function eventAdd(e, event, handler) {
    		if (e.addEventListener) e.addEventListener(event, handler, false);
    			else e.attachEvent('on' + event, handler);
    	}
    
    	function target(e) {
    		e = e || window.event;
    		return e.target || e.srcElement;
    	}
    	
    	function optReplace(e, index) {
    		e = target(e);
    		for (var i = 0; i < e.length; i++) textReplace(
    			e.options[i], e.options[i][index]
    		);
    	}
    	
    	var
    		textGet = (
    			d.body.textContent ?
    			function(e) { return e.textContent; } :
    			function(e) { return e.innerText; }
    		),
    		textReplace = (
    			d.body.textContent ?
    			function(e, text) { e.textContent = text; } :
    			function(e, text) { e.innerText = text; }
    		),
    		
    		// end of libs, start of code unique to this script
    		
    		selectList = d.getElementsByTagName('select'),
    		select, option, i, j;
    	
    	for (i = 0; i < selectList.length; i++) {
    		select = selectList[i];
    		if (classExists(select, 'hasTitles')) {
    			for (j = 0; j < select.length; j++) {
    				option = select[j];
    				option.title = textGet(option);
    				textReplace(option, option.value);
    			}
    			eventAdd(select, 'focus', function(e) { optReplace(e, 'title'); });
    			eventAdd(select, 'blur', function(e) { optReplace(e, 'value'); });
    			eventAdd(select, 'change', function(e) { target(e).blur(); });
    		}
    	}
    		
    })(document);
    I've put a live demo of this up here:
    http://www.cutcodedown.com/for_other.../template.html

    as with all my examples the directory:
    http://www.cutcodedown.com/for_others/brainDonor/

    is unlocked for easy access to the gooey bits and pieces.

    Hope this helps.
    Last edited by deathshadow; 08-02-2014 at 09:00 PM.
    Java is to JavaScript as Ham is to Hamburger.

  5. #5
    Join Date
    May 2014
    Posts
    893
    Oh, word of warning, none of these techniques (mine or anyone elses) works worth a flying purple fish in ANY version of IE. It just doesn't like it. It's just another reason NOT to waste time even trying to do this, and instead just make room in the layout. Kind of like how people use scripting or abuse PLACEHOLDER to do the LABEL tag's job -- when they should just make room for the bloody label.
    Java is to JavaScript as Ham is to Hamburger.

  6. #6
    Join Date
    Dec 2005
    Location
    FL
    Posts
    7,377
    @deathshadow

    In your code of post #4, where is the class 'hasTitles' defined?

  7. #7
    Join Date
    May 2014
    Posts
    893
    Quote Originally Posted by JMRKER View Post
    @deathshadow

    In your code of post #4, where is the class 'hasTitles' defined?
    In the markup right there:
    Code:
    <select id="s1" name="list1" class="hasTitles">
    You put that class on any SELECT you'd like the scripting to target, and boom, it's targeted. I would use getElementsByClassName for that, but legacy browsers choke on that and/or just don't have that. With selects there isn't usually enough of them on a page for getElementsByTagName and a IF statement to be a performance or code-size issue.

    The crappy cross browser support for getElementsByClassName is why get/getAll equivalents exist in pretty much every JS framework or library... Though I'm really liking the "new" querySelector / querySelectorAll. It will be REALLY nice when the day comes that's all we need.

    If you mean for CSS, it doesn't need it. It's used as a hook for scripting, not style -- though if you WANTED to use it for style, it's there and available.

    I've used classes to pass data and target things from scripting for ages; it's part of why the new "data" attributes from HTML 5 are pointless redundancies to me, as if there's enough data for them to make sense, that data should be in the scripting not the markup... if it's for small targeting of elements, that's a class' job.
    Last edited by deathshadow; 08-02-2014 at 10:37 PM.
    Java is to JavaScript as Ham is to Hamburger.

  8. #8
    Join Date
    Nov 2010
    Posts
    1,084
    Quote Originally Posted by deathshadow View Post
    Oh, word of warning, none of these techniques (mine or anyone elses) works worth a flying purple fish in ANY version of IE.
    my code from post#2 works fine in IE8, as does JMRKER's from post #3

    yours does weird things on the width of the select. I'd have a look why, but it's late, so...

  9. #9
    Join Date
    May 2014
    Posts
    893
    Doesn't work here in any of them at all... well, unless that's "Real" IE8 vs. IE11's emulation.

    Since IE11's emulation none of these work 'right', though they all screw up differently.
    Java is to JavaScript as Ham is to Hamburger.

  10. #10
    Join Date
    Nov 2010
    Posts
    1,084
    AH, yeah - I think I remember something now about IE freaking out when you update content in nested tags dynamically.

    Or something like that.

    Still - it's no reason to give up. Whatever happened to "write it for real browsers, hack it for IE?"

    Maybe IE would be happier if you destroy and rebuild the whole thing every time?

    Code:
    <body>
    
    <select id="s1" name="list1">
     <option value="L1">L1</option>
     <option value="L2">L2</option>
     <option value="L3">L3</option>
    </select><br>
    <button id="s1Pick">Show Pick</button>
    
    <script>
    
    (function() {
      var IDS = 's1', selidx = -1, thesel = document.getElementById(IDS), opts = {
            "L1": "L1 - This is long description 1",
            "L2": "L2 - This is long description 2",
            "L3": "L3 - This is long description 3",
        };
        
        thesel.onfocus = function (){changeIt(true)};
        thesel.onblur = function (){changeIt(false)};
        thesel.onchange = thesel.blur;
    
        function changeIt(lng) {
    	selidx=thesel.selectedIndex;
            var cnt = 0;
    		thesel.length=0;
            for (var i in opts) { 
    		var val =lng?opts[i]:i;
    		thesel[cnt++] = new Option (val, i);
    		}
    	thesel.selectedIndex=selidx;	
        }
    
    // allows access to both value and option contents
      document.getElementById(IDS+'Pick').onclick = showPick;
      function showPick() {
        var sel = document.getElementById(IDS);
        var str = 'selectedIndex: '+selidx+'\n';
            str += 'value: '+sel.value+'\n';
            str += 'option: '+opts[sel.value];
        alert(str);
      }
    
    
    })();
    </script>
    
    </body>

  11. #11
    Join Date
    May 2014
    Posts
    893
    I just wouldn't do it in the first place -- again, make room in the layout for it rather than screwing around with scripttardery and code bloat over what's really a non-issue. To me this is the type of "designer choice" that needs a good swift kick in the crotch. If you can't make room for something as simple as a select, you probably shouldn't be making layouts.

    No matter what the artsy fartsy types say. Again, it's reminiscent of the abuse of swapping placeholder text on focus/blur or using HTML 5's placeholder instead of putting a proper LABEL on the element. The artsy types might think it looks neat, but anyone who knows anything about accessibility or usability is going to scream "FALSE SIMPLICITY" in your face as their hand whips up knife-hand like a DI who's about to go batty.

    Though it's sad how many developers right now seem to be saying "**** accessibility and usability" and come up with lame excuses to justify it like a second rate washout from marketing school.

    Basically my advice: don't waste time wasting code to do something you probably shouldn't be doing in the first place. JHVH forbid you make room for the SELECT.

    Though if you REALLY insist on it, my "hack for IE" would be to use the markup I provided, and NOT send the scripting to IE. That way in IE they get the normal select, REAL browsers get the scripted one.

    NOT that I'd actually do that.
    Java is to JavaScript as Ham is to Hamburger.

  12. #12
    Join Date
    May 2003
    Location
    Milwaukee
    Posts
    344
    Thanks for the insights, guys!

    Some background info on this project: We are an IE shop...the internal form I am working on will potentially have hundreds of rows and there will be three places where I will be using these select lists for three different data items in each row. Many of the descriptions are 30 or more characters, which is why I want to only show the codes on the form. The user will need to see what the descriptions are when they need to override the codes in the select lists. Hope this makes sense.

    I am going to start taking a look at the help you guys have provided. Again, thank you so much!! I truly appreciate the time you've taken.

    Tom

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
HTML5 Development Center



Recent Articles