1

I have this module naija passed to a template from the controller like this:

 res.render('testing',   {title:"filter setting page", 
                            nigeria:naija
                            });
   

nigeria.states() generates the list of states in Nigeria into a select options successfully with this code:

select.form-select.col-xs-12.col-sm-12(id='selState1', onChange='listLgas(nigeria, this)')
                  each state in nigeria.states()
                    option(value='#{state}') #{state} 

I want to use the selected state from the select element above to generate the list of local governments in another select when the onChange event of the select above triggers like this

select.form-select.col-xs-12.col-sm-12(id='selLga1')
                  script(type='text/javascript'). 
                    function listLgas(nigeria, element){
                      var selectedState;
                      console.log('inside setState')
                      element = this
                      var selectedOption = element.value
                      console.log(selectedOption );
                      lgas=nigeria.lgas(selectedOption )
                      console.log(lgas)
                      selLga1 = document.getElementById('selLga1')
                      selLga1.innerHTML =''
                      lgas.forEach(function(lg){
                        selLga1.add(new Option(lg,lg));
                      }) 
                    }

The problem is, I get 'nigeria is not defined' from onChange='setState(nigeria, this)'

I changed the event listener to onChange= 'listLgas(this)', hoping nigeria should be available globally in the template. This time i get 'nigeiria is not defined' in listLgass().

How do I make nigeria available to use in the event handler?

3
  • Firstly, ensure that Nigeria is passed as a parameter to the listLgas function from the onChange event: select.form-select.col-xs-12.col-sm-12(id='selState1', onChange='listLgas(naija, this)') Commented May 14 at 11:12
  • Then, in your event handler function listLgas, accept nigeria as a parameter: function listLgas(nigeria, element) { var selectedState = element.value; var lgas = nigeria.lgas(selectedState); var selLga1 = document.getElementById('selLga1'); selLga1.innerHTML = ''; lgas.forEach(function(lg) { selLga1.add(new Option(lg, lg)); }); } Commented May 14 at 11:13
  • Thnaks for your resoinse. Did that already, it didnt work. Kindly go through my question and the code.
    – Femi
    Commented May 14 at 14:00

1 Answer 1

0

The problem is that naija object contains methods, which are functions, and when you send it via .render method, it will be stringified, and JSON does not support functions (see: json.stringify does not process object methods), so they will be lost in the process, and undefined when used in pug template, either way you pass it.

So, don't send object with methods in .render, send (JSON) values instead, and implement relevant methods with JavaScript on the client (or simply use the module by loading it via script tag), not with pug and passed template variables, and you can make required data available to JavaScript:

 res.render('testing', {
    title: "filter setting page",
    nigeria: {
        states: naija.states(),
        lgas: naija.lgas()
    }
 });
<!-- make data global -->
script.
    const nigeria = !{JSON.stringify(nigeria)};
    console.log(nigeria)
script(type='text/javascript').
function lgas(args) {
    // need to implement required methods
    // here or include in a separate JS file, but not via JSON object
2
  • Thanks. But I am thinking, would there then be a need to pass the module from the controller then, shouldn't we just re-write the modules in plain javascript either in the template or in a js file?
    – Femi
    Commented Jun 1 at 23:26
  • yes, as I suggested, in that case it should be included on the client or re-written or similar, but not sent via res.render, which is meant to contain local variables, as in JSON objects, not JS modules, functions, classes etc. In this case, I'd just extract lgas and other needed methods, which you could write directly in the view, or in separate JS file, and then in res.render send data they need, and make it available to JS, for example, const nigeria = !{JSON.stringify(nigeria)};
    – traynor
    Commented Jun 2 at 6:40

Not the answer you're looking for? Browse other questions tagged or ask your own question.