Javascript onload не срабатывает

Привет, ребята,

Это, возможно, довольно простой вопрос, я больше бэкенд-разработчик. Сейчас я пытаюсь подключить JavaScript-код к элементу фронтенда. Проблема в том, что мой window.onload (и document.onload, я пробовал оба варианта) никогда не срабатывает. Мой JavaScript находится в папке инициализации плагина ([plugin]/assets/javascripts/initializers/[plugin].js.es6):

export default {
  name: "meritmoot",
  initialize() {

    // моя функция инициализации
    function initializeMeritmoot(api) {
      console.log("inside initializeMeritmoot")

      // функция на событие keyup
      function repInputKeyUp() {
        inputBox = document.getElementById("rep-input")
        console.log("in rep input key up")
        ajax("/reps/search/" + inputBox.value +".json", {type: 'GET'}).then((result) => {
          console.log(result)
          result = JSON.parse(result)
          repList = document.getElementById("rep-list")
          repList.innerHTML = ""
          result.forEach(op => {
            var x = document.createElement("INPUT");
            x.setAttribute("info-tag-id", op.id)
            x.setAttribute("value", op.mm_reference_str)
            repList.appendChild(x)
          });
          console.log(repList)
        });
      };
      console.log("Past Function Def");
      
      // загрузка окна (не происходит)
      window.onload = () => {
        console.log("PageLoaded") <-----------------------------------это никогда не выводится
        document.getElementById('rep-input').onkeyup = repInputKeyUp;
      };
      console.log('leaving initializeMeritmoot');
    }
    console.log("MeritMoot Javascript In Default")
    withPluginApi("0.8.37", api => initializeMeritmoot(api));
  }
};

Есть ли у кого-то идеи, почему это может происходить? Правильно ли настроен этот JavaScript в контексте Discourse? Или это более общая проблема JavaScript?

Редактирование: пытаюсь добавить addEventListener…

Редактирование: заменил onload на:

  window.addEventListener('onload', function() {
    console.log("PageLoaded")
    document.getElementById('rep-input').onkeyup = repInputKeyUp;
  }, false);

это тоже не сработало

Вы работаете с EmberJS, а не с чистым JavaScript. Поведение будет отличаться.

Лучше следовать лучшим практикам EmberJS.

Я бы рассмотрел возможность встроить вашу логику в существующий компонент или добавить его в слот плагина, используя хук didInsertElement.

Прочитайте руководство EmberJS

Спасибо! Я видел, что Ember играет важную роль в Discourse, но не понимал, что он заменяет стандартный функционал. Я выделю время и изучу его.

edit: Я использую плагин element discovery-list-container-top и подключаюсь к архитектуре плагинов на Ruby.

edit: Какая связь между ember-rails и Discourse? Сам по себе Ember кажется полноценной средой разработки. Посмотрите на GitHub - emberjs/ember-rails: Ember for Rails 3.1+ · GitHub

ember-rails — это Ruby-гем, который фактически используется в Discourse.

Сотрудники Discourse могут дать более точные комментарии, но в целом EmberJS отвечает за фронтенд, а Ruby on Rails — за бэкенд. Конечно, в архитектуре Discourse есть уникальные элементы, и точная конфигурация, как и в любом крупном приложении, в той или иной степени индивидуальна.

Хорошее описание того, как всё устроено, можно найти здесь: Creating Routes in Discourse and Showing Data

Документация по API доступна здесь: https://docs.discourse.org

За последнее время я многому научился в Ember.js, но, похоже, использовал неправильную версию. Насколько я могу судить, Discourse использует Ember.js 1.9 (судя по документации ember-rails и синтаксису исходного кода). Текущая версия Ember.js — 3.17. Поэтому руководствоваться следует этим руководством. Синтаксис довольно отличается, но я разобрался с основами. Когда закончу, опубликую приведенный выше код, переделанный под Ember.js.

Запуск dev-инстанса в браузере показывает следующее в консоли JavaScript:

DEBUG: -------------------------------
DEBUG: Ember  : 3.12.2 
DEBUG: jQuery : 3.4.1 
DEBUG: ------------------------------- 

Но вы правы, некоторые соглашения Discourse не отражают самый последний синтаксис в руководствах :slight_smile:

Спасибо за помощь, Роберт! Немного времени я чувствовал себя не в своей тарелке. В любом случае, вот что у меня в итоге получилось, как и обещал. Я решил использовать функцию onload, которая срабатывает после загрузки DOM. Сначала я пробовал использовать jQuery, но потом узнал, что Ember.js отказывается от него.

import { ajax } from 'discourse/lib/ajax';
// Можно было бы обновить подсветку, чтобы она работала и при split(" "). Если, конечно, захочется.

export default Ember.Component.extend({
  runOnceRan: false,
  myAws: "",
  subbedReps: [],
  // Обновляем предлагаемые варианты для представителей в поле ввода
  updatePossibles: function (substr) {
    var compContext = this; // контекст компонента
    if (substr == "") {
      return;
    }
    // Получаем подсказки
    substr = encodeURIComponent(substr);
    ajax(`meritmoot/reps/search/${substr}.json`, { type: "GET" }).then( result => {
      result = result.api;
      let pv = []; // возможные значения
      for(let i = 0; i < result.length; i++) {
        let newItem = {
          label: result[i].mm_reference_str,
          value: result[i].id,
          id: result[i].id,
        }
        pv.push(newItem);
      }
      console.log(pv)
      compContext.myAws.list = pv;
      // Обновляем внутреннюю логику Awesomplete
      compContext.myAws.evaluate();
      // Показываем подсказки Awesomplete
      compContext.myAws.open();
    });
  },
  runOnce: function () {
    // Сообщаем, что функция выполнилась...
    console.log("in runOnce")
    const substrInput = document.getElementById("rep-input");
    const compContext = this;
    
    // Создаём кастомный Awesomplete (список опций) для substrInput (rep-input).
    this.myAws = new Awesomplete(substrInput);
    console.log(substrInput)

    // Все элементы списка должны отображаться, так как фильтрация по значению substr уже не применяется
    this.myAws.filter = function (text, input) {
      return true
    }

    // Показывать всегда, включить автодополнение.
    this.myAws.minChars = 0;
    this.myAws.autocomplete = "on";

    // Обработка выбора опции.
    document.addEventListener('awesomplete-selectcomplete', function(e) {
        if(e.srcElement == substrInput) {
          let id = e.text.value;
          substrInput.value = "";
          
          // Отправляем выбор на бэкенд
          let uriid = encodeURIComponent(id)
          ajax(`meritmoot/reps/${uriid}`, {type: "PUT" }).then( result => {
            console.log("put passed back:");
            console.log(result);
          });

          // Обновляем выбор на фронтенде
          let l = compContext.get("subbedReps");
          l.pushObject(id) // нужен pushObject вместо push (https://github.com/emberjs/ember.js/issues/10405)
          compContext.set("subbedReps", l);

          // 1. DONE создать таблицу, сопоставляющую ID пользователя с подписанными представителями.
          // 2. DONE создать способ добавления подписанных представителей в эту таблицу. в процессе (нужны GET, PUT, DELETE)
          // 3. отображать представителей рядом с substrInput
          // 3. создать способ отображения голосов рядом с темами.
          // 4. после всего этого обновить механизм отображения голосов здесь.
        }
      }, false);
    
    // Получаем сохранённых пользователем представителей и отображаем их.
    ajax(`meritmoot/reps`, {type: "GET"}).then( result => {
      console.log("get passed back:");
      console.log(result);
      compContext.set("subbedReps", result.mmfollows);
      console.log("subbedReps")
      console.log(compContext.get("subbedReps"));
    });

    // При вводе обновляем подсказки
    document.addEventListener('input', function(e) {
        if(e.explicitOriginalTarget == substrInput) {
          compContext.updatePossibles(substrInput.value);
        }
      }, false)
    console.log(this.myAws);
  },
  didRender() {
    this._super(...arguments);
    if( ! this.runOnceRan ) {
      this.runOnce();
      this.set("runOnceRan", true);
    }
  }
});