blog?

Break On Attribute Change

13 June 2016

Today I discovered a neat feature available in both Firefox and Chrome: break on attribute change. This allows us to break when some code changes a DOM element attribute.

I was debugging an issue where some code involved with adding and removing styles for error indication on a table was incorrectly doing the following:

$("td").each(function() {
    if (!$(this).hasClass("qc-error")) {
        $(this.parentNode).attr("style", "");
    } else {
        $(this.parentNode).attr("style", "border: 1px solid #f00; background: #eee");
    }
});

The templating code was responsible for the initial hiding of the row and would insert this style when rendered:

<tr id="second-fee-row" ${'style="display: none"' if bid.fee_type != constants.FEE_TYPE_PER else '' | n}>

Additionally, some code elsewhere on the page was also attempting to manage this row by setting the display in response to changes in a dropdown:

if ($("#fee-type").val() !== constants.FEE_TYPE_PER) {
    $("#second-fee-row").css("display", "none");
} else {
    $("#second-fee-row").css("display", "table-row");
}

After first verifying that Firefox thought it should display the element, I looked at the page source. Checked out. display: none was definitely there.

Then I spent some time looking for modifications to #second-fee-row. I inspected all the sites that were modifying that row (by looking for that id). Nope. Nothing setting the style to empty.

After a quick google to confirm that display: none hadn't suddenly become unsupported, I came across this Stack Overflow link: https://stackoverflow.com/questions/13303650/break-when-style-has-changed-in-chrome-dev-tools. This in turn led me to search for the same feature in Firefox (my day-to-day browser) which resulted in: https://getfirebug.com/doc/breakpoints/demo.html.

I went ahead and set such a breakpoint on the afflicted element. Lo and behold, the offending code was found and repaired with:

$("td").each(function() {
    if (!$(this).hasClass("qc-error")) {
        $(this.parentNode).css({
            border: null,
            background: null
        });
    } else {
        $(this.parentNode).css({
            border: "1px solid #f00",
            background: "#eee"
        });
    }
});

Not a perfect solution (should probably track the original value instead) but acceptable in this case.