При интеграции карт Яндекс в решения на базе 1С:Предприятие разработчики часто сталкиваются с фундаментальной проблемой: попытка вернуть результат работы функции JavaScript обычным оператором return не приносит успеха. Это происходит потому, что работа с картами (построение маршрутов, геокодирование) осуществляется асинхронно. Когда 1С вызывает функцию JS, ответ от серверов Яндекса еще не получен, и функция завершается раньше, чем данные становятся доступны.
В данной статье мы подробно разберем, как обойти это ограничение, проанализируем механизмы взаимодействия между веб-контентом и платформой 1С, а также рассмотрим рабочие примеры кода для обычных и управляемых форм.
Рассмотрим ситуацию: мы вызываем расчет расстояния. В коде JavaScript это выглядит как создание объекта router. Метод получения данных является асинхронным, то есть он принимает "функцию обратного вызова" (callback), которая сработает только тогда, когда сервер Яндекса пришлет ответ. Программа 1С, вызывая функцию через Document.parentWindow, не ждет этого ответа и моментально получает undefined или пустую строку.
Чтобы решить эту задачу, нам нужно инвертировать логику: не 1С должна "забирать" значение, а JavaScript должен "сообщать" 1С, что данные готовы. Выясним, какими способами это можно реализовать.
Этот метод отлично подходит для обычных форм и ранних версий 8.3. Суть заключается в том, чтобы имитировать нажатие на элемент HTML-документа изнутри кода JavaScript. 1С перехватывает это событие в процедуре-обработчике ПриНажатии (или onclick).
Шаг 1. Подготовка HTML-макета
Добавим в наш HTML скрытый элемент (например, кнопку или поле ввода), который будет служить каналом передачи данных.
<input type="hidden" id="Rasstoyanie" value="">
<button id="TriggerButton" style="display:none;" onclick="return true;"></button>
Шаг 2. Код в JavaScript
В функции обработки успешного построения маршрута мы записываем значение в поле и программно вызываем событие клика на кнопке.
function DobavitMarshrut(Tochka1, Tochka2) {
var router = new YMaps.Router([Tochka1, Tochka2]);
YMaps.Events.observe(router, router.Events.Success, function() {
var distance = router.getDistance();
// Записываем результат в скрытое поле
document.getElementById('Rasstoyanie').value = distance;
// Генерируем событие нажатия для 1С
var btn = document.getElementById('TriggerButton');
btn.fireEvent("onclick");
});
}
Шаг 3. Обработка в 1С
В свойствах элемента ПолеHTMLДокумента на форме 1С выберем событие onclick (или ПриНажатии). В обработчике мы считаем данные.
Процедура КартаПриНажатии(Элемент, ДанныеСобытия)
// Проверяем, что событие пришло именно от нашей кнопки
Если ДанныеСобытия.Element.id = "TriggerButton" Тогда
Расстояние = Элемент.Документ.getElementById("Rasstoyanie").value;
Сообщить("Расстояние получено: " + Расстояние);
КонецЕсли;
КонецПроцедуры
В управляемых формах прямое использование fireEvent может быть затруднено. Более надежным способом является установка флага готовности в JavaScript и его периодическая проверка со стороны 1С. Рассмотрим этот алгоритм подробнее.
JavaScript часть:
Создадим глобальную переменную-флаг DataChanged.
var DataChanged = false;
var DistanceValue = 0;
function MakeRoute(coords) {
ymaps.route(coords).then(function (route) {
DistanceValue = route.getLength();
DataChanged = true; // Сигнализируем о готовности
});
}
1С часть (Управляемая форма):
После вызова функции построения маршрута мы запускаем цикл проверки.
&НаКлиенте
Процедура ПостроитьМаршрут()
// Вызываем JS функцию
Элементы.ЯндексКарта.Документ.defaultView.MakeRoute(МассивКоординат);
// Подключаем обработчик ожидания, который сработает через 1 секунду
ПодключитьОбработчикОжидания("ПрочитатьДанныеСКарты", 1, Ложь);
КонецПроцедуры
&НаКлиенте
Процедура ПрочитатьДанныеСКарты()
// Обращаемся к контексту JS окна
JSWindow = Элементы.ЯндексКарта.Документ.defaultView;
Если JSWindow.DataChanged Тогда
// Данные готовы — считываем их
ОтключитьОбработчикОжидания("ПрочитатьДанныеСКарты");
Результат = JSWindow.DistanceValue;
JSWindow.DataChanged = false; // Сбрасываем флаг
Сообщить("Результат расчета: " + Результат);
КонецЕсли;
КонецПроцедуры
Если вы используете платформу версии 8.3.14 и выше, программный интерфейс ПоляHTMLДокумента позволяет использовать объект window.external. Это наиболее "чистый" способ передачи данных из браузера в 1С без костылей с кнопками.
В JavaScript:
Проанализируем, как передать данные одной строкой. Мы можем использовать JSON для передачи сложных структур.
function sendTo1C(data) {
if (window.external && window.external.notify) {
window.external.notify(JSON.stringify(data));
}
}
// Пример вызова в callback API карт
ymaps.route(points).then(function(route) {
var info = {
distance: route.getLength(),
duration: route.getTime()
};
sendTo1C(info);
});
В 1С:
Используйте событие ВнешнееСобытие (для некоторых конфигураций) или специализированный обработчик ПриНажатии (в зависимости от настроек компонента). В новых версиях платформы реализовано событие ТекстУведомления в объекте ПолеHTMLДокумента.
При передаче значений из JavaScript в 1С помните о следующих нюансах:
Число(), предварительно заменив точку на запятую, если этого требуют региональные настройки 1С.JSON.stringify() в JS и ЧтениеJSON в 1С. Это избавит вас от проблем с парсингом строк.window.focus().Таким образом, мы выяснили, что ключ к успешному возврату значений из Yandex API в 1С лежит в использовании событийной модели. Выбор конкретного метода (скрытая кнопка, флаг в обработчике ожидания или window.external) зависит от версии вашей платформы и типа используемых форм.