Asp.Net ScriptManager вызывает проблемы с jQuery Widget

Я использую ScriptManager и виджет слайдера jQuery вместе на сайтах в течение многих лет, но недавно я столкнулся с проблемой, которая остановила работу виджета. Мне удалось решить проблему, но это было больше не повезло, чем опыт. Я надеюсь, что кто-то может обосновать эту проблему и что исправление может оказаться полезным для других с той же проблемой.

Я использую агрегатор script, который объединяет мои скрипты вместе - вот что он содержит - все фрагменты кода были сокращены для краткости:

vendor/Modernizr.min.js
vendor/jQuery.3.0.0.min.js
vendor/jQuery-UI.1.12.1.min.js
vendor/jQuery-UI.TouchPunch.min.js
propriertary/LoanSelector.js
DefaultInit.js

Вот содержимое DefaultInit.js:

$(document).ready(function () {
    loanSelector.init();
});

Вот голые кости LoanSelector.js

var loanSelector = function () {

    var pub = {}, $ctl = $("#loan-selector"),
        $sliderAmount = $ctl.find(".slider-amount:first"),
        $widgetAmount = $sliderAmount.find(".widget:first");

    function initControl() {
        initWidgetAmount(100, 2000, 100, $("#hfStartAmount").val());
    }

    function initWidgetAmount(min, max, step, initialVal) {
        $widgetAmount.slider({
        });
    }

    pub.init = function () {
        initControl();
    };

    return pub;
} ();

Теперь это работает, но только без ScriptManager на странице.

Когда добавлен менеджер script, виджет слайдера не загружается - никаких ошибок - ничего.

Кэшированные элементы являются постоянными светильниками на странице, поэтому это не случай, когда элементы не существуют в определенный момент времени.

Здесь код ScriptManager:

    <asp:ScriptManager ID="SM" runat="server"
        EnableCdn="true"
        LoadScriptsBeforeUI="false"
        EnablePageMethods="true">
    </asp:ScriptManager>

Если я вношу изменения, я могу заставить виджет загружать ScriptManager на странице - вот еще одна версия LoanSelector.js, которая работает:

var loanSelector = function () {

    var pub = {}, $ctl, $sliderAmount, $widgetAmount;

    function cacheElements() {
        $ctl = $("#loan-selector"),
        $sliderAmount = $ctl.find(".slider-amount:first"),
        $widgetAmount = $sliderAmount.find(".widget:first");
    }

    function initControl() {
        // This is new
        cacheElements();

        initWidgetAmount(100, 2000, 100, $("#hfStartAmount").val());
    }

    function initWidgetAmount(min, max, step, initialVal) {
        $widgetAmount.slider({
        });
    }

    pub.init = function () {
        initControl();
    };

    return pub;
} ();

Итак, может кто-нибудь пролить свет на то, почему он может не работать и почему исправление работает?

Ответ 1

Первый метод заполняет переменные по мере их выполнения:

var pub = {}, $ctl = $("#loan-selector"),
    $sliderAmount = $ctl.find(".slider-amount:first"),
    $widgetAmount = $sliderAmount.find(".widget:first");

So #loan-selector, .slider-amount:first и .widget:first должны отображаться на странице DOM до того, как это будет вызвано.

Второй вариант заполняется, когда вызывается loanSelector.init(), а по месту в вашем коде, где вы его называете, DOM загружается.

<asp:ScriptManager> дает вам коллекцию элементов управления скриптами на стороне сервера, которую можно легко добавить, но она отображает список тегов <script> и порядок может быть важным - другой элемент управления на странице может означать, что DOM вы полагаясь на то, что не загружен ко времени запуска вашего кода. Скрипты выполняются по порядку, но не дожидаются завершения рендеринга DOM.

jQuery имеет собственную структуру компонентов, которую вы можете использовать вместо этого, и метод DOM ready, на который вы можете положиться - вы уже используете его в DefaultInit.js, поэтому loanSelector.init() может получить доступ к DOM, а непосредственно Выполненный код не работает.

У вас уже есть исправление, а вторая script - лучшая практика, потому что она не зависит от времени выполнения.

Другой альтернативой может быть вызов вашей функции loanSelector в $(document).ready:

$(function(){
    // In this DOM ready function your elements should be ready to find
    var loanSelector = ...
    ...

    // And you may not need this, as you can init in the actual function
    loanSelector.init();
});