Javascript onload not firing

AI-generated summary

Javascript onload not firing

Luke_Clancy is having trouble with the window.onload event not firing in their JavaScript code, which is part of a Discourse plugin. They are using the plugin element discovery-list-container-top and connecting to a Ruby backend plugin architecture.

Merefield points out that Discourse uses EmberJS, which overrides vanilla JavaScript behavior. They recommend following EmberJS best practices, such as using the didInsertElement hook or piggybacking onto an existing component.

Luke_Clancy learns about EmberJS and its version used in Discourse (1.9) and starts converting their code to EmberJS. However, they realize that the current version of EmberJS is 3.17, and the syntax has changed.

Merefield reveals that the Discourse instance is actually running Ember 3.12.2, not 1.9.

Luke_Clancy shares their converted code, which uses Ember Component and the didRender hook to execute the code after the DOM is loaded. They also use the ajax function from discourse/lib/ajax to make requests to the backend.

Hey guys,

This may be a bit of a basic question, I am more of a back-end guy. Currently I am trying to connect some java-script code to a front end element. The issue is that my window.onload (and document.onload, I tried them both) never fires. my javascript is in the plugin init folder ( [plugin]/assets/javascripts/initializers/[plugin].js.es6 )

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

    //my initialization function
    function initializeMeritmoot(api) {
      console.log("inside initializeMeritmoot")

      //function on key up
      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 load (doesnt happen)
      window.onload = () => {
        console.log("PageLoaded") <-----------------------------------this never prints
        document.getElementById('rep-input').onkeyup = repInputKeyUp;
      };
      console.log('leaving initializeMeritmoot');
    }
    console.log("MeritMoot Javascript In Default")
    withPluginApi("0.8.37", api => initializeMeritmoot(api));
  }
};

Any thoughts on why this may be? Is this javascript setup correctly in relation to discourse? Or is this more of a general javascript thing?

Edit: trying addEventListener…

Edit: substituting onload for:

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

did not work either

You are working with EmberJS here, not vanilla JavaScript. It will not behave the same.

Best to follow EmberJS best practice.

I would consider piggybacking your logic onto an existing component or adding one to a plugin outlet and using the didInsertElement hook.

Read the EmberJS Guides

Thanks! I saw ember was a big part of discourse, but didn’t realize it overrode vanilla. Ill take a time and learn it.

edit: I am using the plugin element discovery-list-container-top and connecting to a ruby backend plugin archetecture

edit: Whats the relation between ember-rails and discourse? Ember by itself seems to be a full stack enviroment. Looking at GitHub - emberjs/ember-rails: Ember for Rails 3.1+ · GitHub

ember-rails is a Ruby gem that is actually used in Discourse.

Discourse staffers are far better to comment, but broadly, EmberJS deals with the front-end, and Ruby-on-Rails, the back end. Of course, Discourse has elements of a bespoke architecture and the exact configuration is, like any big application, at least somewhat unique.

A nice description of the way things work is here Creating Routes in Discourse and Showing Data

The API docs are here https://docs.discourse.org

Learned a lot of emberjs over the last bit - but it looks like on the wrong version. As far as I can tell Emberjs 1.9 is used by discourse (by looking at the ember-rails docs and source code syntax). Current version of Emberjs is 3.17 So the guide that should be followed is this one. The syntax is quite diffrent, but I got the basics down. I will post the above code converted to emberjs when finished

Running a dev instance in a browser reveals this in the javascript console:

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

But you are right, some of the Discourse conventions don’t reflect the very latest syntax on the guides :slight_smile:

Thanks for the help Robert, I was kind of out of my depth on this for a bit! Anyway, here is what I got in the end as promised. I ended up using the onload function, which triggers after the DOM is loaded. I tried to use jquery for a bit until I heard that emberjs was depreciating it.

import { ajax } from 'discourse/lib/ajax';
//could update the highlight to hit on the split(" ") aswell. If, you know, i feel like it.

export default Ember.Component.extend({
  runOnceRan: false,
  myAws: "",
  subbedReps: [],
  //update the suggested options to follow for representatives in the input box
  updatePossibles: function (substr) {
    var compContext = this; //component context
    if (substr == "") {
      return;
    }
    //get suggestions
    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;
      //update Awesomplete internal logic
      compContext.myAws.evaluate();
      //show Awesomplete suggestions
      compContext.myAws.open();
    });
  },
  runOnce: function () {
    //let us know it ran...
    console.log("in runOnce")
    const substrInput = document.getElementById("rep-input");
    const compContext = this;
    
    //create custom Awesomplete (options list) for substrInput (rep-input).
    this.myAws = new Awesomplete(substrInput);
    console.log(substrInput)

    //all list items should be shown, as they are selected with predjudice on substr value change
    this.myAws.filter = function (text, input) {
      return true
    }

    //show whenever, turn autocomplete on.
    this.myAws.minChars = 0;
    this.myAws.autocomplete = "on";

    //on selection of option, handle it.
    document.addEventListener('awesomplete-selectcomplete', function(e) {
        if(e.srcElement == substrInput) {
          let id = e.text.value;
          substrInput.value = "";
          
          //send selection backend
          let uriid = encodeURIComponent(id)
          ajax(`meritmoot/reps/${uriid}`, {type: "PUT" }).then( result => {
            console.log("put passed back:");
            console.log(result);
          });

          //update selection frontend
          let l = compContext.get("subbedReps");
          l.pushObject(id) //pushObject is needed instead of push (https://github.com/emberjs/ember.js/issues/10405)
          compContext.set("subbedReps", l);

          //1. DONE create a table that matches user id to subscribed reps.
          //2. DONE create a way to add subscribed reps to that table. in progress (need GET PUT DELETE)
          //3. view reps next to substrInput
          //3. create a way to view votes next to topics.
          //4. after all that, refresh that mechanism of viewing votes here.
        }
      }, false);
    
    //get users saved representatives, show them.
    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"));
    });

    //on input, update suggestions
    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);
    }
  }
});