0

Frontend I can access methods of an instance of a class by static code:

instanceName.method(varValue);

The class is Gauge (library SVG Gauge) and with the above code I can control the pointer of my instanced gauge as expected. I can also control it with pre-render generated code in EJS:

<%= gaugeInstanceVar %>.setValue(<%= gaugeValueVar %>);

But I am getting a variable in through Server Sent Events after rendering and gaugeInstanceVar, containing the name of the instance used thus:

gaugeInstanceVar.method(varValue) throws: Uncaught TypeError: X.setValue is not a function.

It also feels wrong to me, like failing to modify my variable, when I really want to use the value to call the instance.

What however would be the correct way of accessing the method (in my current case ".setValue()" of an active instance of a Class, using the variable gaugeInstanceVar?

Edit:

Using eval() would also achieve the desired effect

eval(sseTopic).setValue(sseValueNumber);

But I believe I should stay away from it and am still looking for the correct way of achieving the equivalent.

Edit 2 (feedback for Bergi)

I have condensed the code down to one if the 7 gauge types, here switch case 3.

The user input is just via form, everything apart from the code below is handled backend.

The library "SVG Gauges" takes the var to create the instance of Gauge. The divs with corresponding id's are created one step earlier - I don't think we need that code here.

EJS provides element.topic for the var, as well as the id, which is desired.

<%
data.forEach( element=> {

switch(element.gaugetype) {

case 'gauge3':
gaugeClass ='gauge-container three'; // used for div's
%> 
<script>var <%= element.topic %> = Gauge(document.getElementById('<%= element.topic %>'), {
max: <%= element.value %>,
value: 50
} );</script>
<%
break;

default:
return;
break;
} %>

After removeSpecialCharacters(string) the variable sseTopic in the code below is identical with element.topic in the code above.

  //Server Sent Event-Handler
  let sse = new EventSource("http://localhost:3000/sse-stream");

    sse.onmessage = function (event) {
    let jdata = JSON.parse(event.data);

    let sseValue = jdata.message;
    let sseValueNumber = Number(sseValue);

    let rawSseTopic = jdata.topicname;
    let sseTopic = removeSpecialCharacters(rawSseTopic);

    sseTopic.setValue(sseValueNumber); // Type ERROR not a function

    // eval(sseTopic).setValue(sseValueNumber);    not desirable b
  };

  function removeSpecialCharacters(string) {
    let cleanString = string.replace(/,|\.|-|_|\|\s|\//g, "");
    return cleanString;
  }
  • 1
    Possible duplicate: ["Variable" variables in JavaScript](https://stackoverflow.com/q/5187530) et al. The best way to deal with this is to either store the instance in a wrapper object (`const instances = { [yourInstanceNameHere]: { /* ... */ } }`) or refactor your code so that you won't have to refer to your variables using their names. – InSync May 07 '23 at 05:40
  • I am probably missing something here and will delve more into Classes before I continue. I was not able to derive my solution from the suggested answer. So you are saying I should create that wrapper object while the instances are created (forEach loops), so that I can call methods later. – DegreeInNoobology May 07 '23 at 15:45
  • @DegreeInNoobology No, you should not create wrapper objects. And the question seems to be not about calling dynamic methods by name, but rather about accessing instances by name. The solution to that is to not go by variable names but rather to put all of the instances that you want to access into a collection where you can look them up. – Bergi May 07 '23 at 16:30
  • TY for getting back. I have no static list of instances. Users can add gauges to their dashboard and the server will send live data accordingly. If the user has created a gauge called "factory/machines/machine201/temperature" the code removes certain chars and names an instance accordingly. The message coming in contains the same name that I need to use for setting a new value. Can I update that collection dynamically? – DegreeInNoobology May 07 '23 at 22:39
  • Yes, you can and should (need to) update the list dynamically. Please show us the code that is adding the gauge to a user's dashboard (derives the name, updates the SSE, creates the new instance of the gauge, adds it to the DOM) if you need help with this – Bergi May 07 '23 at 22:47
  • @Bergi your help is much appreciated. I have edited my question and added the respective code. – DegreeInNoobology May 07 '23 at 23:26
  • Try to avoid emitting dynamic code. Emit the data as an object/array (serialised to JSON), and add a script that iterates the data and adds the gauges. Do not declare variables with dynamic names. Create a collection (e.g. `new Map`) and set the gauges as elements. – Bergi May 07 '23 at 23:33

0 Answers0