Showing posts with label forms. Show all posts
Showing posts with label forms. Show all posts

Friday, March 29, 2013

Use javascript to set text (with newlines) into a textarea - for IE and Firefox

Keywords:
javascript jquery textarea DOM innerHTML newlines carriage return whitespace IE firefox chrome

Problem:
Setting text with newlines into a textarea using the innerHTML attribute:
<textarea id="source" rows="4" cols="50">
A
B
C
</textarea>
<button onclick="copyText();return false;">copy -></button>
<textarea id="target" rows="4" cols="50">
</textarea>


<script type="text/javascript">
    function copyText() {
        var sourceField = document.getElementById('source');
        var targetField = document.getElementById('target');
        targetField.innerHTML = sourceField.value;
    }
</script>

Works in "most" browsers but in IE the text put into the textarea has the newline characters stripped out (replaced with a single space character). Is there a way to make this work in IE? ... and most other browsers?

Solution:
To make it work in IE, setting the text via inputField.setAttribute("value", [your text]); will preserve the newlines (i.e. the "\n" character in javascript)
var sourceField = document.getElementById('source');
var targetField = document.getElementById('target');
targetField.setAttribute("value",sourceField.value);

Only problem is that setting the attribute alone is not enough for Firefox (& Chrome - all WebKit?). For the above example, the target field will not appear to have the value from the source (though the DOM will have the value). To get them all to work? Contrive the order in which you set things:
var sourceField = document.getElementById('source');
var targetField = document.getElementById('target');
var text = sourceField.value;
targetField.innerHTML = text; // now Firefox (& Chrome) are happy - but IE has the text as one line
targetField.setAttribute("value", text); // now IE has the text as multiple lines - the change should be imperceptible 

The same code using jQuery (note that jQuery's html() function will still use innerHTML ultimately so is subject to same IE issue with newlines being stripped):
jQuery(document).ready(function($){
    var text = $(sourceField).val();
    $(targetField).html(text);
    $(targetField).val(text);
}); 

Notes:
Use of innerHTML for managing textarea content - and keeping it in-synch with the DOM - was discussed in the previous post: Firefox does not reflect input form field values via innerHTML. I'll update that post accordingly ...

Friday, January 16, 2009

GWT Button acts as a submit in WebKit browsers

Keywords:
HTML button element form WebKit Chrome Safari iPhone

Problem:
In WebKit browsers, the Button widget in a GWT application seems to always act as a submit, regardless of event sinking (via ClickListener) behaviour added to it.

In Firefox (and IE!) the button works fine - that is the 'onclick' behaviour added to the widget via the GWT listening architecture is executed and the page is not submitted.

Solution:
A clue to the solution is in the code for the GWT Button (thank goodness for source code - see Button.adjustType(Element button)).

It seems to be a work around for Firefox. The W3C spec states that the default value for button type is 'submit'. Firefox does this explicitly in the DOM and when detected, this is fixed by the GWT JSNI (JavaScript Native Interface) code.

It would seem that for WebKit browsers this default is enforced but not made explicit in the DOM so this GWT snippet does not get a chance to resolve the issue. The work around is to always be explicit about the button type (as recommended in W3Schoools).

You do this in GWT as follows:
     Button b = new Button("click here");
     DOM.setElementAttribute(b.getElement(), "type", "button");

Thursday, August 16, 2007

Firefox does not reflect input form field values via innerHTML

Keywords:
firefox innerHTML form input field value text select textarea

Problem:
In IE (and therefore the GWT test shell running on windows) you can call innerHTML on a DOM object and where it contains HTTP form input fields you will see an up-to-date reflection of the inputs from the user.

On firefox you simply get a reflection of the DOM as it was originally served up to the user.

This is a problem if you want to move HTML around and not loose the inputs already made by the user.

Eg: On clicking the button in firefox you won't see the input entered in the text box.
<form action="" method="get">       
    <SPAN id="MyContent">           
        <input type="text" name="textField" value="" /><br/>
    </SPAN>
</form>           
  
<button onClick="window.alert(MyContent.innerHTML);">discover user input</button>


Solution:
Found the solution on comp.lang.javascript - Firefox does not reflect selected option via innerHTML. I've extended the example code from this post to handle checkbox, radio and textarea ...

The idea is, every input field on the page must have an onBlur="updateDOM(this)" event handler, forcing the DOM to be updated and reflect the user's input.
<script type="text/javascript">
//
// Will be called by input fields when in 'update DOM' mode. This will
// make sure that changes to input fields in the form will be captured
// in the DOM - not necessary in IE but is required in Moz, etc as the DOM
// will otherwise reflect the page as it was initially.
//
// inputField : the input field that has just been tabbed out of (onBlur) OR the ID of the input field
function updateDOM(inputField) {
    // if the inputField ID string has been passed in, get the inputField object
    if (typeof inputField == "string") {
        inputField = document.getElementById(inputField);
    }
    
    if (inputField.type == "select-one") {
        for (var i=0; i<inputField.options.length; i++) {
            if (i == inputField.selectedIndex) {    
                inputField.options[i].setAttribute("selected","selected");
            } else {
                inputField.options[i].removeAttribute("selected");
            }
        }
    } else if (inputField.type == "select-multiple") {
        for (var i=0; i<inputField.options.length; i++) {
            if (inputField.options[i].selected) {
                inputField.options[i].setAttribute("selected","selected");
            } else {
                inputField.options[i].removeAttribute("selected");
            }
        }
    } else if (inputField.type == "text") {
        inputField.setAttribute("value",inputField.value);
    } else if (inputField.type == "textarea") {
        var text = inputField.value;
        inputField.innerHTML = text;
        inputField.setAttribute("value", text);
    } else if (inputField.type == "checkbox") {
        if (inputField.checked) {
            inputField.setAttribute("checked","checked");
        } else {
            inputField.removeAttribute("checked");
        }
    } else if (inputField.type == "radio") {
        var radioNames = document.getElementsByName(inputField.name);
        for(var i=0; i < radioNames.length; i++) {
            if (radioNames[i].checked) {
                radioNames[i].setAttribute("checked","checked");
            } else {
                radioNames[i].removeAttribute("checked");
            }
        }
    }
}
</script>

<form action="" method="get">        
    <SPAN id="MyContent">            
        <input type="text" name="textField" value="" onBlur="updateDOM(this)"/><br/>
    </SPAN>
</form>            
    
<button onClick="window.alert(MyContent.innerHTML);">discover user input</button>


Notes:
It gets slightly trickier if you have input fields that don't get filled in by the user - eg a date picker dropdown, which will set the textbox with the date for the user, hence they never click in the box and trigger the 'onBlur'. In this case, you'd put the onBlur event on the date picker button

Eg:
<input type="text" name="dateField" id="dateField" value="" onBlur="updateDOM(this)"/>
<button id="myDatePicker" onClick="... do datepicking stuff ..." onBlur="updateDOM('dateField')">
 ... date picking image ...
</button>


Post updated (Thu, 25 Mar 2010): With thanks to the helpful commentors, the above script incorporates better handling for textArea & radio fields as well as an issue I came across for 'select-multiple' (was missing from the original script). It should work fine with the update via document or form approaches discussed in the comments - as opposed to the onBlur which continues to be good enough for my usage.

Post updated (Fri, 5 Apr 2013): Beware trying to set innerHTML text with newlines - IE will lose them. Work around is set the value attribute afterwards and this will honour the newlines (and is meaningless for other browsers).

Tuesday, January 23, 2007

GWT POST request doesn't include parameters

Keywords:
GWT POST request parameters HTTP HTML RequestBuilder AJAX

Problem:
Following the GWT documentation for making a http-post but it's not clear what the post data should look like if you want it to include form parameters. The newer documentation for com.google.gwt.http.client has a bit more detail but the server side code processing the request (a java servlet) says there's no parameters in the request.

Solution:
It's not in the documentation, but if you want to post form data you must set the "Content-type" header value in the request to "application/x-www-form-urlencoded"

For Example:
StringBuffer postData = new StringBuffer();
// note param pairs are separated by a '&' 
// and each key-value pair is separated by a '='
postData.append(URL.encode("YourParameterName")).append("=").append(URL.encode("YourParameterValue"));
postData.append("&");
postData.append(URL.encode("YourParameterName2")).append("=").append(URL.encode("YourParameterValue2"));

RequestBuilder builder = new RequestBuilder(RequestBuilder.POST, "/yourserver/formprocessor"));
builder.setHeader("Content-type", "application/x-www-form-urlencoded");
try {
  builder.sendRequest(postData.toString(), this /* or other RequestCallback impl*/);
} catch (RequestException e) {
  // handle this
}


Notes:
This sample chapter from the JavaScript™ Phrasebook is useful: Sending a POST Request