JavaScript Styling of DIV

Discussion in 'JavaScript' started by martin12532, Nov 25, 2012.

  1. #1
    Hi guys,

    Having a little trouble with using Javascript to style a div "on the fly". I'm currently creating a sign up membership form in which I'd like the input text box's holding DIV to change colour depending on if the text box has been filled in. For example, I have written some Javascript code that will change the surrounding div to a yellow colour when the text box is 'onfocus', I have then made the JS check to see if the text box has been filled when 'onblur'. It then changes to red if nothing has been typed in the box or back to the default colour if something has. Happy! But...

    I'd like to use this piece of JS code on all of the input text fields in my form which would mean I'd have to re-type and adapt the code (adding IDs name1, name2, name3 etc) to the various different div IDs. Is there a way to use the 'this.style' trick to use the same code on all the divs without having to re-type (and make my JS file unnecessarily big)?

    Many thanks


    The JavaScript Code:
    
    function changeBackground()
    {
        document.getElementById("name1").style.background="#FFFFe0";    
    }
    
    function checkBackground()
    {
        var x=document.forms["applicationForm"]["firstNameInput"].value;
            
            if (x=="") 
      {
      document.getElementById("name1").style.background="#ffaaaa";    
      }
                    
            else 
      {
      document.getElementById("name1").style.background="#e6e8e9";    
      }        
            
    }
    
    Code (markup):
    HTML Code:
    
    <form id="applicationForm" action="appForm.php" method="post">
                        
                        
                        
                   <div id="name1"  class="inputHolder">
        
                           <div class="formTitle">
                              <p>First Name</p><p style="color:red;">&nbsp;*</p>
                                                     
                            </div><!--formTitle-->
                                    
                            <div class="formInput">
                                <input type="text" name="firstNameInput"  onfocus="changeBackground()" onblur="checkBackground()">
                                                     
                            </div><!--formInput-->
                           
                             </div><!--inputHolder-->
    
    
    
                    <div id="name2"  class="inputHolder">
        
                           <div class="formTitle">
                              <p>Surname</p><p style="color:red;">&nbsp;*</p>
                                                     
                            </div><!--formTitle-->
                                    
                            <div class="formInput">
                                <input type="text" name="surNameInput"  onfocus="changeBackground()" onblur="checkBackground()">
                                                     
                            </div><!--formInput-->
                           
                             </div><!--inputHolder-->
    
                             </form>
    
    Code (markup):
     
    martin12532, Nov 25, 2012 IP
  2. deathshadow

    deathshadow Acclaimed Member

    Messages:
    9,732
    Likes Received:
    1,999
    Best Answers:
    253
    Trophy Points:
    515
    #2
    First I would advise against using the 1997 style FORMS array, it's unreliable and outdated... and as a rule doesn't target ID's, it targets NAME. Second I'd suggest losing all the endless pointless DIV -- and I'd also suggest that you start using LABEL for your... uhm... labels... (instead of abusing paragraphs for christmas only knows what reason) and your comment placement (between block level elements) could also trip rendering bugs.... might also help if the indenting was meaningful/consistent. (also proves what a joke K&R formatting is).

    Seriously, that markup is some serious whiskey-tango-foxtrot territory.

    A few less DIV would also make it easier to target the parent element for styling, and I'd use a class there so that multiple styles are easily added or changed without diving into the scripting. (rule of thumb, if you have to say STYLE in your scripting, you're doing it all wrong). It also helps in these situations to have the script apply it's hooks itself, instead of saying "onblur" and "onfocus" a few dozen times in the markup. A single class can be used to say "checkme" if you put the script after the markup.

    Czech this out:
    
    <style type="text/css">
    #applicationForm div {
    	padding:0.5em;
    	background:#FAA;
    }
    
    #applicationForm .modifying {
    	background:#FFE;
    }
    
    #applicationForm .filled {
    	background:#E6E8E9;
    }
    
    label b {
    	color:red;
    }
    
    fieldset {
    	border:0;
    	padding:0;
    	margin:0;
    }
    
    </style>
    
    <form id="applicationForm" action="appForm.php" method="post">
    	<fieldset>
    	
    		<div id="name1">
    			<label for="firstNameInput">First Name <b>*</b></label><br />
    			<input
    				type="text"
    				name="firstNameInput"
    				id="firstNameInput"
    				class="checkIfFilled"
    			/>
    		<!-- #name1 --></div>
    		
    		<div id="name2">
    			<label for="surnameInput">Surname <b>*</b></label><br />
    			<input
    				type="text"
    				name="surNameInput"
    				id="surNameInput"
    				class="checkIfFilled"
    			/>
    		<!-- #name2 --></div>
    		
    	</fieldset>
    </form>
    
    <script type="text/javascript">
    var inputList=document.getElementsByTagName('input');
    for (t=0; t<inputList.length; t++) {
    	if (inputList[t].className='checkIfFilled') {
    		inputList[t].onfocus=function() {
    			this.parentNode.className="modifying";
    		}
    		inputList[t].onblur=function() {
    			this.parentNode.className=(this.value=='') ? '' : 'filled';
    		}
    	}
    }
    </script>
    
    Code (markup):
    The script pulls up a list of inputs, checks if their class is "checkIfFilled" -- if so, it applies the functions. The functions change the class on the immediate parentNode, which should be the DIV surrounding them. A more robust version would split the className so multiple classes don't get in the way and add/remove classes as necessary.
     
    deathshadow, Nov 25, 2012 IP
  3. martin12532

    martin12532 Greenhorn

    Messages:
    10
    Likes Received:
    0
    Best Answers:
    0
    Trophy Points:
    11
    #3
    Thank you for your advice.

    How would I go about using this same method of my next input box was a textarea box as the JS is looking for the 'input' tag..?

    Many thanks again, I'll definitely be sure to take your comments on board.
     
    martin12532, Nov 25, 2012 IP
  4. deathshadow

    deathshadow Acclaimed Member

    Messages:
    9,732
    Likes Received:
    1,999
    Best Answers:
    253
    Trophy Points:
    515
    #4
    That just involves pulling a list of textareas. In THEORY we could use getElementsByClassName, but that doesn't exist in older browsers and to be frank, isn't all that reliable in modern ones. The polyfills most use to implement getElementsByClassName often drag older browsers into the 9th ring of Oblivion on performance and can be some hefty code, so it's better to just use what works everywhere.

    I cleaned it up a bit, added the check for textareas, and used regex to make sure that the routine doesn't need multiple classes. Since the functions are relationship based (targeting 'this' and 'parentNode') I also show here how you don't actually need the ID's on the wrappers.

    
    <style type="text/css">
    #applicationForm div {
    	padding:0.5em;
    	background:#FAA;
    }
    
    #applicationForm .modifying {
    	background:#FFE;
    }
    
    #applicationForm .filled {
    	background:#E6E8E9;
    }
    
    label b {
    	color:red;
    }
    
    fieldset {
    	border:0;
    	padding:0;
    	margin:0;
    }
    
    </style>
    
    <form id="applicationForm" action="appForm.php" method="post">
    	<fieldset>
    	
    		<div>
    			<label for="firstNameInput">First Name <b>*</b></label><br />
    			<input
    				type="text"
    				name="firstNameInput"
    				id="firstNameInput"
    				class="checkIfFilled"
    			/>
    		</div>
    		
    		<div>
    			<label for="surnameInput">Surname <b>*</b></label><br />
    			<input
    				type="text"
    				name="surNameInput"
    				id="surNameInput"
    				class="checkIfFilled"
    			/>
    		</div>
    		
    		<div>
    			<label for="messageTextarea">Message <b>*</b></label><br />
    			<textarea
    				type="text"
    				name="messageTextarea"
    				id="messageTextarea"
    				class="checkIfFilled"
    			></textarea>
    		</div>
    		
    	</fieldset>
    </form>
    
    <script type="text/javascript">
    
    function setupModifyFilled(tagName) {
    	tagList=document.getElementsByTagName(tagName);
    	for (var t = 0; t < tagList.length; t++) {
    		if (tagList[t].className.search(/\bcheckIfFilled\b/) >= 0) {
    		
    			tagList[t].onfocus=function() {
    				with (this.parentNode) {
    					className = className.replace(/\bfilled\b/,'');
    					if (className.search(/\bmodifying\b/) == -1) {
    						className += " modifying";
    					}
    					className = className.replace(/\s+/,' ');
    				}
    			} // onfocus
    			
    			tagList[t].onblur = function() {
    				with (this.parentNode) {
    					className = className.replace(/\bmodifying\b/,'');
    					if (this.value == '') {
    						className = className.replace(/\bfilled\b/,'');
    					} else if (className.search(/\bfilled\b/) == -1) {
    						className += ' filled';
    					}
    					className = className.replace(/\s+/,' ');
    				}
    			} // onblur
    			
    		}
    	}
    }
    
    setupModifyFilled('input');
    setupModifyFilled('textarea');
    </script>
    Code (markup):
    The whitespace condensing regex /\s+/ is in there to prevent the string from filling up with too many spaces after multiple use of the replace function. Putting the setup in a function also means it's not polluting the namespace (as much)

    In theory you could even get rid of the DIV by using the label as the wrapper, but honestly I'd probably keep the block level container since label is a inline-level element and input/textarea are a 'special inline'. (SHOULD be inline-block, that's how Opera treats them -- but Mozilla and M$ have different ideas on that).

    Hope this helps.
     
    deathshadow, Nov 26, 2012 IP
  5. martin12532

    martin12532 Greenhorn

    Messages:
    10
    Likes Received:
    0
    Best Answers:
    0
    Trophy Points:
    11
    #5
    Thank you very much! You obviously know your stuff!

    You say my coding is old fashioned and 'whiskey-tango-foxtrot territory'. This is the way that I've learned from reading online and looking at 'view source' of sites I like. Are there any books or websites you'd recommend for me to bring my coding upto scratch and more modern?

    Many thank yous!
     
    martin12532, Nov 27, 2012 IP