views:

373

answers:

7

Still looking for an answer.

Changing or reassigning to the filter's innerHTML successfully redraws the element, but breaks my script, so that's out.

Adding additional child nodes, including text nodes, does not force a redraw. Removing the added node does not force a redraw.

Using the ie7.js family of scripts does not work.


In the project I am working on, I dynamically generate (with javascript) filters that look like this:

<div class="filter">
    <a ... class="filter_delete_link">Delete</a>
    <div class="filter_field">
        ...
    </div>
    <div class="filter_compare">
        ...
    </div>
    <div class="filter_constraint">
        ...
    </div>
    <div class="filter_logic">
        ...
    </div>
</div>

And I have CSS that applies to each filter (for example):

.filter a.filter_delete_link{
    display:block;
    height:16px;
    background: url('../images/remove_16.gif') no-repeat;
    padding-left:20px;
}

However, it seems in IE 7 (and probably 6 for that matter), these styles don't get applied to the new filters.

Everything works perfectly in Firefox/Chrome/IE8.

Using the IE8 developer tools, set to IE7 mode, the browser can see the new elements, and can see the CSS, but just isn't applying the CSS.

Is there a way to force IE to reload styles, or perhaps is there a better way to fix this?


The JavaScript: (simplified)

var builder = {
    ...
    createNewFilter: function() {
        var newFilter = document.createElement('div');

        var deleteLink = document.createElement('a');
        deleteLink.href = '#';
        deleteLink.setAttribute('class','filter_delete_link');
        deleteLink.title = 'Delete Condition';
        deleteLink.innerHTML = "Delete";
        newFilter.appendChild(deleteLink);

        var field = document.createElement('div');
        field.setAttribute('class','filter_field');
        var fieldSelect = this.getFieldSelectBox();
        field.appendChild(fieldSelect);
        newFilter.appendChild(field);

        // more of the same...

        deleteLink.onclick = function() {
            builder.removeFilter(newFilter);
        };
        fieldSelect.onchange = function () {
            builder.updateFilter(newFilter);
        }

        return newFilter;
    },
    addNewFilter: function() {
        var nNewFilter = this.createNewFilter(this.numFilters++);
        this.root.insertBefore(nNewFilter,this.nAddLink);

        //other unrelated stuff...

        //provided by Josh Stodola
        //redraw(this.root);

        return nNewFilter;
    }
}
A: 

Could it be that you're missing " at the end of some elements?

<a ... class="filter_delete_link>Delete</a> missing "
<div class="filter_field> missing "
fredrik
Just a typo. Fixed now.
Austin Hyde
A: 

You have a missing " on the line that reads <a ... class="filter_delete_link>Delete</a>

Edit:
I don't think it's a problem with IE7 as it seems to work fine here - http://jsfiddle.net/nhvrA/.
I'll keep investigating.

Sam
no, just a typo. Fixed now.
Austin Hyde
I'm not using jQuery (I'd like to be, *grumble, grumble*). Perhaps jQuery has some code to reload styles?
Austin Hyde
+1  A: 

IE6/7 has a lot of problems/bugs/misbehaviours with regard to creating and adding elements in the DOM using createElement. I strongly recommend to switch to jQuery for this since it does all the work in a cross browser compatible manner and has already taken (almost) all the IE6/7 specific misbehaviours into account so that you don't need to end up with a doubled amount of code to get it to work in all browsers the world is aware of. Here's a copy'n'paste'n'runnable SSCCE:

<!doctype html>
<html lang="en">
    <head>
        <title>Test</title>
        <script src="http://code.jquery.com/jquery-latest.min.js"&gt;&lt;/script&gt;
        <script>
            $(document).ready(function() {
                $('#add').click(function() {
                    var newElement = $('<div class="filter"><a href="#" class="delete">delete</a></div>');
                    $('#container').append(newElement);
                });
            });
        </script>
        <style>
            .filter { background: pink; }
            .delete { background: yellow; }
        </style>
    </head>
    <body>
        <div id="container"></div>
        <button id="add">add</button>
    </body>
</html>

Update: as per the comments, jQuery is absolutely not an option. Well, best what you can try is to set element attributes only after the element is been added to the DOM. Also try not to clone nodes in IE6/7, this is often epic fail. Rather create a brand new node from beginning on.

BalusC
Wish I could switch to jQuery, its what I normally use. However, it's not an option right now :(
Austin Hyde
Why not? Anyway, try to set element attributes *after* the element is been added to the DOM. Also try not to clone nodes in IE6/7, this is often epic fail. Rather create a brand new node from beginning on.
BalusC
Well, I'm adding attributes before, and cloning, so I'll try to fix that.
Austin Hyde
Well, just to see if that was the problem, I tried this (attributes before adding and cloning): http://jsfiddle.net/YMDrQ/. In IE 6/7, it works perfectly.
Austin Hyde
+2  A: 

Sounds to me like you need to force a redraw of the UI for this element. There are several ways to do this, but the following is the most effective method...

// elm is a reference to your element
var disp = elm.style.display;
elm.style.display = "none";
var redrawFix = elm.offsetHeight;
elm.style.display = disp;

Here is another method I found on Ajaxian...

function redraw(elm) {
  var n = document.createTextNode(' ');
  elm.appendChild(n);
  setTimeout(function(){ n.parentNode.removeChild(n) }, 0);
  return elm;
}
Josh Stodola
well, the first method doesn't work, and the second method fails because IE doesn't know what `Function.prototype.defer` is.
Austin Hyde
@Austin Whoops, you're right. `defer` is a Prototype (JS framework) function that holds the function call until the interpreter is idle. I've updated my answer to not depend on that framework function, but instead use a similiar method.
Josh Stodola
I understand what you're trying to do. However, it's not working. I tried changing the timeout to wait longer, and did not work. I tried just leaving the extra node in. No result. What does work is `elm.innerHTML += ' ';`, but that screws up my events (not sure why), so I need to get rid of the space.
Austin Hyde
Updated my question with javascript.
Austin Hyde
A: 

Don't you need a width as well as a height on the element? I know display: block should give it width: 100%, but IE is not that bright. Does anything change if you provide a width?

Tom
I actually do give it a width in another style.
Austin Hyde
+3  A: 

The problem, I've discovered is that IE 6/7 doesn't register the class name changes with elm.setAttribute('class','x') until the UI is redrawn.

The solution is to use the form elm.className = 'x'

Austin Hyde
Thanks for posting, struggled with this tedious bit for a while.
dalbaeb
A: 

Building off of other comments and answers in this thread, I resolved this problem using the Prototype library:

<div id"dynamically-added-block"> ... </div>
...
$("dynamically-added-block").up().show();

Simply, get the parent and re-show it. Tested in IE8, using both Browser Mode: IE8, Document Mode: IE8 and Browser Mode: IE7, Document Mode: IE7. Have not tested with the dreaded quirks mode.

Found this reference:http://www.evotech.net/blog/2009/03/ie8-css-support/Suggesting that the following meta tag is needed: <meta http-equiv="X-UA-Compatible" content="IE=7" />