JavaScript onload 이벤트가 실행되지 않음

여러분 안녕하세요,

조금 기초적인 질문일 수 있지만, 저는 백엔드 개발자입니다. 현재 자바스크립트 코드를 프론트엔드 요소에 연결하려고 하고 있습니다. 문제는 window.onload(그리고 document.onload, 둘 다 시도해 보았습니다)가 절대 실행되지 않는다는 것입니다. 제 자바스크립트는 플러그인 init 폴더( [plugin]/assets/javascripts/initializers/[plugin].js.es6 )에 있습니다.

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

    //초기화 함수
    function initializeMeritmoot(api) {
      console.log("inside initializeMeritmoot")

      //키 업 이벤트 함수
      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));
  }
};

이것이 왜 그런지 아이디어가 있으신가요? 이 자바스크립트가 discourse에 대해 올바르게 설정된 것인가요? 아니면 일반적인 자바스크립트 문제인가요?

수정: addEventListener를 시도해 보고 있습니다…

수정: onload 대신 다음을 사용했습니다:

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

하지만 이것도 작동하지 않았습니다

여기서는 순수 JavaScript가 아니라 EmberJS를 사용하고 있습니다. 동작 방식이 동일하지 않습니다.

EmberJS의 모범 사례를 따르는 것이 가장 좋습니다.

기존 컴포넌트에 로직을 추가하거나, 플러그인 아웃렛에 컴포넌트를 추가하고 didInsertElement 훅을 사용하는 것을 고려해 보세요.

EmberJS 가이드를 읽어보시기 바랍니다.

감사합니다! Ember가 Discourse의 큰 부분을 차지한다는 것은 알았지만, Vanilla를 오버라이드한다는 사실은 몰랐어요. 시간을 내서 배우겠습니다.

수정: 플러그인 element discovery-list-container-top을 사용하고 있으며, Ruby 백엔드 플러그인 아키텍처에 연결하고 있습니다.

수정: ember-rails와 Discourse의 관계는 무엇인가요? Ember 자체는 풀스택 환경처럼 보입니다. GitHub - emberjs/ember-rails: Ember for Rails 3.1+ · GitHub 를 보고 있습니다.

ember-rails는 실제로 Discourse에서 사용되는 Ruby gem입니다.

Discourse 스태프가 더 정확한 설명을 할 수 있겠지만, 대략적으로 EmberJS는 프론트엔드를, Ruby-on-Rails는 백엔드를 담당합니다. 물론 Discourse는 자체적인 아키텍처 요소를 포함하고 있으며, 어떤 대형 애플리케이션이든 그렇듯이 정확한 구성은 적어도 어느 정도 고유합니다.

동작 방식을 잘 설명해 주는 글은 여기 있습니다: Creating Routes in Discourse and Showing Data

API 문서는 여기 있습니다: https://docs.discourse.org

최근에 emberjs를 많이 배웠는데, 아쉽게도 잘못된 버전을 배운 것 같습니다. 제가 파악한 바로는 discourse는 Emberjs 1.9를 사용하는 것으로 보입니다(ember-rails 문서와 소스 코드 문법을 참고했습니다). 현재 Emberjs 버전은 3.17이므로, 따라야 할 가이드는 이것입니다. 문법은 꽤 다르지만, 기본기는 잡았습니다. 작업을 마치면 위에 언급한 코드를 emberjs로 변환한 것을 게시하겠습니다.

브라우저에서 개발용 인스턴스를 실행하면 자바스크립트 콘솔에 다음 내용이 표시됩니다:

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

맞습니다. Discourse의 일부 관례가 가이드의 최신 문법을 반영하지 못하고 있긴 합니다 :slight_smile:

로버트, 도움 주셔서 감사합니다. 이 부분은 저도 좀 감이 안 와서 헤맸었거든요! 어쨌든 약속대로 최종적으로 정리한 내용을 공유합니다. 결국 DOM이 로드된 후 실행되는 onload 함수를 사용했습니다. 처음에는 jQuery를 사용해보려 했지만, emberjs가 이를 비추천(deprecate)한다는 이야기를 듣고 나서 다른 방법을 찾게 되었습니다.

import { ajax } from 'discourse/lib/ajax';
// split(" ")에 맞춰 하이라이트를 업데이트할 수도 있습니다. 만약, 그러고 싶다면요.

export default Ember.Component.extend({
  runOnceRan: false,
  myAws: "",
  subbedReps: [],
  // 입력 상자에서 대표(representatives)를 위한 추천 옵션을 업데이트
  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 = []; // 가능한 값들(possible values)
      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;
    
    // substrInput(rep-input)을 위한 커스텀 Awesomplete(옵션 목록) 생성.
    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) // push 대신 pushObject가 필요합니다 (https://github.com/emberjs/ember.js/issues/10405)
          compContext.set("subbedReps", l);

          // 1. 완료: 사용자 ID와 구독한 대표를 매칭하는 테이블 생성.
          // 2. 완료: 구독한 대표를 해당 테이블에 추가하는 방법 생성. 진행 중 (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);
    }
  }
});