Клуб API Карт

Как перезапустить API с новым параметром lang без перезагрузки страницы?

Yaroslav Svidchenko
9 апреля, 11:35

Полностью эджексовый сайт. Переключение языков тоже происходит динамической подгрузкой из БД без перезагрузки страницы. Т.к. переключение языков не предусмотрено в  Яндекс картах, то возникает необходимость перезапуска API с новым параметром lang. Перезагрузка страницы недопустима по условиям задачи. Пробовал испытанные способы динамической загрузки внешних скриптов.

Способ 1:

$.ajax({
    type: 'GET',
    url: 'https://api-maps.yandex.ru/2.1/?lang=en_US',
    dataType: "script",
    cache: true,
    success: function() {
        init();
    }
});

Способ 2:

var script = document.createElement('script');
if (script.readyState && !script.onload) {
    // IE, Opera
    script.onreadystatechange = function() {
        if (script.readyState == "loaded" || script.readyState == "complete") {
            script.onreadystatechange = null;
            init();
        }
    }
}
else {
    // Rest
    script.onload = function() {
        init();
    };
}
script.src = 'https://api-maps.yandex.ru/2.1/?lang=en_US';
document.getElementsByTagName('head')[0].appendChild(script);

В обоих случаях получаю TypeError: ymaps.Map is not a constructor. С обычным статическим прописыванием в <head> все работает.  Обгуглил все, что можно, странно, что мало кто сталкивался с этой проблемой.

9 комментариев
https://tech.yandex.ru/maps/doc/jsapi/2.1/dg/concepts/load-docpage/#api-ready
Yaroslav Svidchenko
10 апреля, 06:37
dimik,
Эту страницу я уже дословно помню. Каждую запятую.  Здесь вообще ничего не сказано о "горячем перезапуске". Только вместе с загрузкой страницы. А мне нужно именно без перезагрузки.
Yaroslav Svidchenko,
Видимо прочитали "по диагонали". То, что вы подключаете – это только загрузчик. Он загружает отдельным вызовом компоненты АПИ
"""
Чтобы быть уверенным, что компоненты загружены и готовы к использованию, необходимо использовать функцию ready или параметр загрузки onload.

"""


var script = document.createElement('script');

script.src = 'https://api-maps.yandex.ru/2.1/?lang=en_US&onload=init';

document.getElementsByTagName('head')[0].appendChild(script);
Yaroslav Svidchenko
11 апреля, 10:25
dimik,
Спасибо, пробовал и так. Да, при загрузке отрабатывает нормально. Но по событию из боди карту с другим языком не загружает. В инит честно заходит, но язык карты не меняется.  Ошибок в консоли нет, что еще хуже т.к. неизвестно куда копать.  Вот упрощенная схема страницы:


<head>
    <script>
         function setLanguage(language)
         {
            $.post("<?php echo Yii::app()->request->baseUrl;?>/jsload/setcookie",

            {name:'language', val:language },
             function(data) {
                 if (language == 'uk') l = 'uk_UA';
                     else
                 if (language == 'ru') l = 'ru_RU';
                     else
                 if (language == 'en') l = 'en_US';
// Всячески пытаемся убить объект myMap если он != undefined или не пытаемся. Пробовал и так и так.

// ----Дальше ваш код----
                    var script = document.createElement('script');
                    script.src = 'https://api-maps.yandex.ru/2.1/?lang=' + l + '&onload=init';
                     document.getElementsByTagName('head')[0].appendChild(script);
//----конец вашего кода----
//Тянем эджексом из БД данные для интерфейса и переназначаем их по всей странице.
             });
         }
     </script>
</head>


<body>
// ---- код страницы ----
     <input type="button" onclick="setLanguage('uk');">
     <input type="button" onclick="setLanguage('ru');">
     <input type="button" onclick="setLanguage('en');">
// ---- код страницы ----
</body>


<script>
     var myMap;
     function init(){
        alert('Зашли в инит')
        myMap = new ymaps.Map("map", {
//---- Стандартный инит по меньюэлу
         });
     }


     setLanguage(Cookies.get('language')); // Запускаем всю цепочку при загрузке. В куки значение есть. Я выбросил из примера все проверки и установки по дифолту.




</script>
Yaroslav Svidchenko,
Нужно вызвать destroy на карте и создать новую. Соберите минимальный пример на jsfiddle, будем смотреть 
Алексей Бендер
11 апреля, 12:10
Данные о языке хранятся внутри API (`ym.env`) и доступа извне к ним нет, вариант с повторной загрузкой лоадера плохой, при этом происходит удвоение экземпляров карты при новых запросах: https://jsbin.com/cacobiruro/2/edit?js,output (возможно, моя ошибка). Если непринципиально, то изменение языка доступно у мапбокс.
Алексей Бендер,
это ваша ошибка, в displayMap подписываетесь на клик по кнопке и не отписываетесь. при след. toggle обработчик вызывается 2 раза 
Алексей Бендер
11 апреля, 12:20
dimik,
:P упустил.
Обновлено 11 апреля, 12:20
Алексей Бендер
11 апреля, 12:28
Алексей Бендер,
quick fix https://jsbin.com/fidahodoyu/edit?js,output