Thursday, December 1, 2011

IE7 Preserve Whitespace Problem and Solution

Overview
Internet Explorer 7 has a well documented problem when it comes to using innerHTML and dynamically generating content which needs to preserve whitespace.  There is a lot information on the Internet about using the CSS properties white-space, word-wrap, and a multitude of other properties, hacks, and tricks to solve this problem.  However I found none of them worked.  After a few days of research I have a simple solution which I will explain here.

The Problem
Here is the problem.  You are building a dynamic website and in your database you have data which is formatted using newlines and spaces and looks like this:

Hello        Doctor             Name
    Continue
Yest..
 ..erday

Tomorrow


Your website is to pull this data from the database and display it on the page.  The implementation to do this will vary greatly, but essentially you will have an empty <div> to hold the data and you'll use jQuery to look up the <div> by ID then you will set the <div>'s HTML content.  Here is a very basic version of this:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
    <head>               
    </head>
    <body>       
        <div id="theData"></div>       
        <script src="jquery-1.6.2.min.js"></script>
        <script>
            var theData = "Hello        Doctor             Name\n    Continue\nYest..\n ..erday\n\nTomorrow";
            $(document).ready(
                function() {
                    $("#theData").html(theData);
                }
            );
        </script>
    </body>
</html>


Of course when you run this in any browser, the white space and newlines in the text will be removed and you will see this on the screen:
Hello Doctor Name Continue Yest.. ..erday Tomorrow

So CSS to the rescue!  Use the font-family and white-space attributes to tell the browser how to format the text in the <div>.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
    <head>
        <style>
            #theData {
                font-family:monospace;
                white-space:pre-wrap;               
            }
        </style>

    </head>
    <body>       
        <div id="theData"></div>

        <script src="jquery-1.6.2.min.js"></script>
        <script>
            var theData = "Hello        Doctor             Name\n    Continue\nYest..\n ..erday\n\nTomorrow";
            $(document).ready(
                function() {
                    $("#theData").html(theData);
                }
            );
        </script>
    </body>
</html>


Of course you quickly realize this works in Firefox and Chrome but not IE (which is why you are reading this).  This resource http://web.student.tuwien.ac.at/~e0226430/innerHtmlQuirk.html gives a good explanation about what is happening in IE.  Although researching this problem will give you a headache, I found a solution which seems to work with all browsers and is quite easy.

The easiest thing to do is to wrap the data with <pre> tags before setting the inner HTML of the <div>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
    <head>
        <style>
            #theData {
                font-family:monospace;
                white-space: pre-wrap;               
            }
        </style>
    </head>
    <body>       
        <div id="theData"></div> 

        <script src="jquery-1.6.2.min.js"></script>
        <script>
            var theData = "Hello        Doctor             Name\n    Continue\nYest..\n ..erday\n\nTomorrow";
            $(document).ready(
                function() {                   
                    $("#theData").html( 

                       "<pre>" + theData + "</pre>" 
                     );
                }
            );
        </script>
    </body>
</html>


That's it!  Of course, remember your CSS has to change now since you need to format #theData pre{} now...

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
    <head>
        <style>
            #theData pre {
                margin:0;
                color:purple;               
            }
        </style>

    </head>
    <body>       
        <div id="theData"></div>       
        <script src="jquery-1.6.2.min.js"></script>
        <script>
            var theData = "Hello        Doctor             Name\n    Continue\nYest..\n ..erday\n\nTomorrow";
            $(document).ready(
                function() {

                    $("#theData").html( 
                       "<pre>" + theData + "</pre>" 
                     );
                }
            );
        </script>
    </body>
</html>

Enjoy!