ajax не находит функцию скрипта - PullRequest
1 голос
/ 09 апреля 2020

Это контекст:

  1. У меня есть скрипт, countrySelect.min. js, который загружается в заголовок страницы php (в других позициях он не работает, поэтому предположим, что это правильно)

        <script src="<?php echo base_url(); ?>assets/owlcarousel/owl.carousel.js"></script>
    
        <script type="text/javascript" src="<?php echo base_url(); ?>assets/js/bootstrap.min.js"></script>
    
        <script type="text/javascript" src="<?php echo base_url('assets/js/commonFunctions.js'); ?>"></script>
    
        <link rel="stylesheet" href="<?php echo base_url('assets/css/countrySelect.css'); ?>">  
    
        <script type="text/javascript" src="<?php echo base_url('assets/js/countrySelect.min.js'); ?>"></script>
    
        <link rel="stylesheet" href="<?php echo base_url('assets/css/countrySelectorStyle.css'); ?>">   
    
  2. этот скрипт используется внутри функции ( initializeLeafletItems ) для применения в правильных позициях в некоторых раскрывающихся списках выбора страны вызывается функция " countrySelect ", применяемая к объектам, обозначенным $ ("# country_selector" + temp_offer_id)

    function initializeLeafletItems(offers){
    
        leaflets_info = {};
        var temp_product_info_id;
        var temp_product_info = {};
        var temp_offer_id;
        var temp_default_country_code;
    
        const observer = new MutationObserver(function(mutationsList, observer) {
          [...]
        )};
    
        [...]
    
        for(var index in offers){
    
            if(offers[index]['package_leaflets']){
    
                temp_default_country_code = offers[index]['defaultCountry'];
                temp_offer_id = offers[index]['id'];
    
                $("#country_selector"+temp_offer_id).countrySelect({
                    defaultCountry: temp_default_country_code,
                    onlyCountries: offers[index]['countries_list'],
                    responsiveDropdown: true,
                });
    
                [...]
            } 
         }
    
  3. эта функция вызывается почти в конце документа, но за пределами оператора $ (document) .ready (function). Работает нормально, без ошибок.

    initializeLeafletItems(<?php echo json_encode($offers); ?>); 
    
  4. проблема : та же функция вызывается при добавлении новых элементов на страницу, если пользователь нажимает кнопку «ПОКАЗАТЬ БОЛЬШЕ». В частности, он вызывается внутри оператора ajax

    function show_offers(render, from_item, to_item, products_id_list, searchedGeneric, searchedMade, searchedCountries, searchedFormats, searchedCurrency, keywords_id){
    
        if (render == 'PCRender') {
    
            $.ajax({
                method:'POST',
                url: ajax_url+'frontController/addRenderScreenOffers',
                data:{  
                              [...]
                },
                dataType:'json',
    
                success:function(res)
                { 
    
                    if(res['rendered_PC_screen_offers'] != 'empty'){
    
                        $("#offers-product tbody").append(res['rendered_PC_screen_offers']);
                        from_item = to_item + 1;
                        to_item = to_item + 10;
                        $("#show_more_button").replaceWith('[...] )">Show More</button>');
    
                        initializeLeafletItems(res['offers']['offers']);
    

В этом случае я получаю эту ошибку

        Uncaught TypeError: $(...).countrySelect is not a function

, как если бы функция не была в та же область действия функции show_offers или ajax вызова. Я нахожу это странным; однако, когда отладчик браузера остановился, я попытался увидеть видимую область, и кажется, что сценарий и его функция уже есть, посмотрите на эти снимки экрана:

enter image description here enter image description here

Я не нашел много ссылок, наверняка не явных, на подобные случаи, так что это действительно поможет иметь идеи по этому поводу. Я прочитал вокруг, в не очень похожих случаях, кто-то, предлагающий перезагрузить скрипт внутри вызова ajax. Даже если я не знаю, что это работает, потому что я еще не пробовал, я думаю, что, поскольку скрипт уже загружен в документ, должен быть способ ссылаться на него в обоих вызовах этой функции. Это правда?

ОБНОВЛЕНИЕ 12/04/2020

Запись на консоль объекта, к которому она применяется .countrySelect Я могу наблюдать, что в рабочем случае ( на следующем рисунке слева) есть связанный плагин countrySelect, в нерабочих нет

enter image description here

По предложению страныВыберите автора Марк, я повторил тест на более простой странице и обнаружил, что он работает как локально (добавление элемента при нажатии кнопки), так и при вызове ajax. здесь следуя коду контроллера и зрителя; поэтому я попытался также на неработающей странице добавить простой тест добавления элементов ввода, нажав кнопку без каких-либо ajax. Даже в этом случае это не работает (но все же это работает на элементах при первой загрузке той же страницы). Есть идеи? кажется, что на этой странице что-то теряется или плохо взаимодействует.

Вот рабочий код на простой странице (https://www.pharmacomparison.com/frontController/countrySelectTest/)

контроллер:

 function countrySelectTest(){

    $this->load->view('countrySelectTest');

}

function countrySelectTestresult(){

    $random = mt_rand(0,999999999);
    $res['html_text']  = '<input type="text" id="country_selector_ajax'.$random.'" name="country_selector_ajax">';
    $res['state']  = 'success';
    $res['random'] = $random;

    echo json_encode($res);
}

зритель

        <head>
        <meta charset="utf-8">
        <title>Country Select JS</title>
        <link rel="stylesheet" href="build/css/countrySelect.css">
        <link rel="stylesheet" href="build/css/demo.css">

                <link rel="stylesheet" href="<?php echo base_url('assets/css/countrySelect.css'); ?>">    
                <link rel="stylesheet" href="<?php echo base_url('assets/css/demo.css'); ?>">  

                <script type="text/javascript" src="<?php echo base_url(); ?>assets/js/jquery.js"></script>
                <script type="text/javascript" src="<?php echo base_url('assets/js/countrySelect.min.js'); ?>"></script>

        </head>
        <body>
        <h1>Country Select JS</h1>
        <form>
        <div class="" id="country">
        <input id="country" type="text">
        <label for="country_selector" style="display:none;">Select a country here...</label>
        </div>

        <button type="submit" style="display:none;">Submit</button>
        </form>
                    <button type="submit"  id="local_test">Local Test</button>
                    <button type="submit"  id="ajax_test">Ajax Test</button>
        <!-- Load jQuery from CDN so can run demo immediately -->

        <script>

        $("#country").countrySelect({
        // defaultCountry: "jp",
        // onlyCountries: ['us', 'gb', 'ch', 'ca', 'do'],
        // responsiveDropdown: true,
        preferredCountries: ['ca', 'gb', 'us']
        });


        </script>

        <script>
        // Make sure we don't run this until after everything else has been loaded.
        // Using the document click handler ensures that everything else is setup first,
        // which ensures we're not cheating and adding our new element before the
        // plugin attaches to form elements the first time.

        $('#local_test').on('click', function(){

        // Step 1: Create a new element from a simulated AJAX request    
        var newInput = $('<input type="text" id="country_selector_local" name="country_selector_local">');

        // Step 2: Add the new element to the page
        $('form').append(newInput);

        // Step 3: Run the plugin on the new element
        $('#country_selector_local').countrySelect({ defaultCountry: 'au' });

        // Step 4: Profit!
        });

        $('#ajax_test').on('click', function(){

                    //the URL return te same content of previous newInput
                    $.ajax({                                                                  

                        url: 'https://www.pharmacomparison.com/frontController/countrySelectTestResult/',  
                        type: "POST",                                                          
                        enctype: 'multipart/form-data',                                      
                        data: {                                                            
                            product_info_id: 'test'                                                                  
                        },  
                        method: 'Post',  
                        dataType: 'json',  

                        success: function(response) {  
                            if(response.state=='error'){                  

                                alert(response.msg);  
                            }                        

                            if(response.state=='success'){  

                                // Step 2: Add the new element to the page
                                $('form').append(response.html_text);

                                // Step 3: Run the plugin on the new element
                                $('#country_selector_ajax'+response['random']).countrySelect({ defaultCountry: 'au' });

                                // Step 4: Profit!  

                            }

                        },



                        error: function(xhr, status, error) {      
        console.log(xhr);
        console.log(status);
        console.log(error);
                            alert("The request returned an error, please alert the site administrators (" + status +").");

                        }    
                    });      
               });


        </script>


        </body>

1 Ответ

1 голос
/ 13 апреля 2020

Проблема в том, что вы повторно инициализируете jquery после initializeLeafletItems(<?php echo json_encode($offers); ?>); вызова в конце. Это сбрасывает контекст jquery и удаляет функцию countrySelect из $ .fn

Позвольте мне объяснить

  1. Обратите внимание, что вы инициализируете jquery не дважды, а три раза в тот же документ.

enter image description here

и

enter image description here

видите, они на линии № 56, 58 и 5134.

Теперь вы звоните
initializeLeafletItems(<?php echo json_encode($offers); ?>); 

на линию # 4701

enter image description here

Теперь, что происходит, когда вы Запустите этот код в строке 4701 Выбор страны прикреплен к одному из jquery, загруженных ранее, и он работает. А затем jquery сбрасывается и countrySelect удаляется из jquery context, поэтому после полной загрузки страницы вы не сможете использовать countrySelect.

Solution.

  1. Должен быть только один jquery вызов (не обязательно, просто хорошая практика, это уменьшит время загрузки вашей страницы)

  2. Любая загрузка jquery вверху в <head> или где-нибудь до <body> и удалите из строки # 5134.

или

загрузите countrySelect.min. js после # 5134 и переместите initializeLeafletItems(<?php echo json_encode($offers); ?>); в document.ready

делать что угодно, просто загрузите countrySelect.min. js после загрузки всех ваших jquery.

FYI: Все jquery, которые вы загружаете, имеют та же версия v3.4.1. Так что я не вижу никакой конкретной причины c загрузить его трижды. Поправь меня, если я ошибаюсь.

Надеюсь, это поможет тебе.

...