Search code examples
javascriptjquerykendo-uijquery-selectorskendo-asp.net-mvc

Excluding on JQuery selector correct in console, code still runs


I'm working on the print styling for forms in a web app which uses Kendo. In short: before printing, I append <div> tags containing each input's value, and hide the input tags. The exception is the Kendo MaskedTextBox, as the mask displays the data as intended, and its raw value does not contain the mask.

It's working as intended for everything else - the inputs are hidden, and only the appended divs are shown.
For the masked textbox, however, the input is shown (correct), but the div is still being appended (incorrect).

HTML structure (copied from Edge Dev Tools (F12)):

<div class="mws-form-col-2-8">
    <label>Masked TextBox</label>
    <span class="k-widget k-maskedtextbox" style="width: 100%;">
        <input class="k-textbox" id="maskTest" name="maskTest"
               value="1234567890" data-role="maskedtextbox"
               style="width:100%" autocomplete="off">
        <span class="k-icon k-i-warning"></span>
    </span>
    <script>kendo.syncReady(...)</script>
    <!-- Appended div here: <div class="inputPrint">1234567890</div> -->
</div>

Print css:

input:not(.k-textbox),
span.k-widget:not(.k-maskedtextbox) {
    display: none!important;
}

Javascript:

This function is bound to the window.onbeforeprint event and is called from $(document).ready() when the media type is "print" (Edge/Chrome can emulate css media type, which I'm using to debug this).

function beforePrint() {
    // exclude input.k-textbox
    $("input:not(.k-textbox)").each(function () {
        // exclude input with .k-maskedtextbox parent
        //if (! $(this).parents(".k-maskedtextbox").length) {
        if ($(this).parents(".k-maskedtextbox").length <= 0) {
            // check if the .inputPrint div already exists
            if ($(this).siblings(".inputPrint").length) {
                // set text of existing
                $(this).siblings(".inputPrint").text($(this).val());
            }
            else {
                // append a div displaying its value to its parent
                $(this).parent().append("<div class='inputPrint'>" + $(this).val() + "</div>");
            }
        }
    });
}

As you can see, the selector on the first line of the function (input:not(.k-textbox)) is the same as in the css.

Display:

Masked TextBox          ←- Label
╭────────────────╮
| (123) 456-7890 |      ←- input
╰────────────────╯
╭────────────────╮
| 1234567890     |      ←- appended div
╰────────────────╯

When I try to figure out how this could have happened by checking some things in the console, this is what I get:

$("#maskTest").is("input:not(.k-textbox)")
false

$("#maskTest").is(".k-textbox")
true

This input should not have even been included in the .each.

$("#maskTest").parents(".k-maskedtextbox").length
1

$("#maskTest").parents(".k-maskedtextbox").length <= 0
false

If it was included, it should not have entered the first if statement.

How is this happening, and how can I fix it?


Solution

  • I discovered that the Kendo MVC wrappers expand the inputs into kendo controls in the kendo.syncReady event, which runs after $(document).ready is complete.

    So on my initial page load, the input I was checking only looked like this:

    <input id="maskTest" name="maskTest" style="width:100%" value="1234567890" />