...

Ожидание события или элемента на форме

Тема в разделе "Примеры решений и дополнительных модулей", создана пользователем serebriakov, 24 май 2022.

  1. serebriakov

    serebriakov Новичок

    Проблема:
    Иногда необходимо дождаться события для выполнения определенного участка кода. Например, получить идентификатор элемента после его появления в DOM. Использование метода setTimeout ведёт к дублированию кода при работе с несколькими объектами или событиями. Также необходимо в каждом случае продумывать задержку или задавать константу, после которой будет выполнен вызов функции. В связи с этим принято решение реализовать собственную функцию, получающую на вход:
    • Check - функция, возвращающая true, если событие произошло, и false - если не произошло.
    • Callback - функция, выполняющаяся после события ( check = true ).
    • Time (необязательный параметр) - задержка в миллисекундах, определяющая задержку перед повторным вызовом check функции.
    • Limit (необязательный параметр) - максимальная глубина стека (количество проверок выполнения события).
    Реализация:
    Создадим модуль, а внутри виджет с расширением корневой компонент.
    upload_2022-5-24_9-27-41.png

    Корневой компонент позволяет создать виджет, код которого будет исполняться на всех страницах при загрузке системы. Это позволяет нам, единожды создав функцию, использовать её на всех виджетах и формах.
    Добавим виджет код на форму компонента с следующим содержимым:
    Код:
    
    <script>
        function 
    wait(checkcallbacktime=100limit=30) {
            if (
    check()) {
                return 
    callback();
            }

            if (!
    limit) {
                return;
            }

            
    setTimeout(() => {
                
    wait(checkcallbacklimit 10 === time*timelimit-1);
            }, 
    time);
        }
    </script>
    Теперь функция wait доступна во всех скриптах.
    Время ожидания перед следующим опросом события увеличивается вдвое, если оставшаяся глубина стека делится на 10 с нулевым остатком. Это позволит постепенно увеличивать задержку для опроса события. По умолчанию time = 100, limit= 30 (суммарное время ожидания события около 15 секунд).
    Пример:
    1. Добавим в приложении поле для ввода текста (имя свойства - hello_world).
    2. Добавим виджет Код с следующим содержимым:
    Код:
    
    <script>
        function 
    checkSelector(selector) {
            if (
    document.querySelector(selector))
                return 
    true;
            return 
    false;
        }

        
    wait(
            function() {return 
    checkSelector("#hello_world")},
            function() {
                
    let helloWorldField document.querySelector("#hello_world");
                
    helloWorldField.value "Hello world";
            }
        );
    </script>
    Теперь, при создании элемента приложения, в поле для ввода увидим "Hello world".
  2. daniyar1997

    daniyar1997 Участник

    Не проще ли использовать:

    $(document).ready(function() {
    func();
    });

    В данном случае функция func() выполнится после полной загрузки DOM.
    В чем преимущество вашего подхода?
  3. ava_var

    ava_var Активный участник

    В некоторых случаях будет действительно достаточно $(document).ready
    Я в своих проектах сталкивался с изменениями DOM, которые были инициированы изменением контекста. Т.е. jquery.ready отработал, а затем на форме что-то изменяется.
    Проблема обычно возникает при следующих обстоятельствах - в виджет Код создается несколько инпутов или через конструктор создана форма с большим количеством полей. Если нам нужно добавить листенер на последний инпут - вот тут и ловим ошибку, что в DOM еще нет элемента.

    Также функция позволяет отследить загрузку файла js из раздела Файлы
    Код:
    
    <script src="<%= UI.widget.filePath %>/mymath.js" />
    <
    script>
    wait(
         () => 
    typeof myMath !=="undefined"},
         () {
              var 
    sum myMath.sum(23);
         }
    );
    </script>
  4. daniyar1997

    daniyar1997 Участник

    Можно попробовать
    Код:
    
    <script defer>
    //Код
    </script>
    Сам не сталкивался с описанной проблемой.