Access variable within dashboard html template sent from function

I'm sending html from a function to the dashboard template node.

The template node only contains:

<div ng-bind-html="msg.payload.html | trusted"></div>

The function node is sending (excludes special character for multi-line string due to forum formatting)

var html=<table>
<tr>
<td><B><U>IDX:</U></B></td>
<td><B><U>Name:</U></B></td>
<td><B><U>Severity:</U></B></td>
<td><B><U>Reason:</U></B></td>
</tr>
<tr ng-repeat="obj in msg.payload.data">
<td>{{ obj.idx }}</td>
<td>{{ obj.name }}</td>
<td>{{ obj.severitylabel }}</td>
<td>{{ obj.reason }}</td>
</tr>
</table>;

msg.payload.html = html;
return msg;

The HTML table headings IDX, Name, Severity etc... all display fine in the template node.

The variables it's set to access, obj.idx and others however are displayed in the template node as text and not interpreted the same way as if the above var html was simply pasted into the template node.

How can I access the obj.idx and others when html is sent from a function node to the template node?

Thanks

Not sure why you are doing it that way. Why not just create the template in the Dashboard template node?

Need to change the html template layout with the function using if statements.

Your function node is outputting a string with "mustache variables" inside it -- so your function node is not doing the string substitutions. Then you are passing that string of text to the ui_template node that plops the whole string into the empty <div> element, which tries to render it as html dom elements -- so again, no variable substitution happening there.

If you want to invoke the mustache substitution logic, you need to have those variable references inside the core template node, set to "mustache" mode.

BTW, both the Angular framework and the mustache interpreter have if/then/else syntax, so you can base your page rendering off the incoming data directly...

I don't suppose there is any chance of an example? :blush:

shrickus, it's a node-red-dashboard template node, not the standard template node.

You haven't answered my question. You appear to have an unnecessary function and haven't explained why so we can't really help further.

You need to instead put the html from the function node into the template node.
Then send your msg.payload.data to the template node, it will handle the rest.

1 Like

So basically if I am understanding correctly, there is no way to dynamically change the html displayed in the dashboard-template-node the way I need?

Eg:

if (y = x){
display x html
}else{ if y = z){
display z html
}

I only want a table displayed in the node if there is data, if there isn't any data I want to display a message "no problems found" or similar.

I think I see what you are saying... I am trying to do the same thing with a table.

I am going to try to build the HTML in a function node with all of the values then send it as plain text to the template.

We would need to iterate through the object and for each property, place the values into the place holders in the html string and then add that string to the next.
Something like this:

for(var prop in object) {
 html += "<tr><td>"+object[prop]+"</td><tr>"
 }
 msg.payload.html = html

This does work, crudely.

var html = ""
var obj = msg.payload[0]
for(var prop in obj) {
    html += "<table class=\"componentTable\">"+
      "<tr style="+"\"background:red\""+">"+
        "<td>"+prop+"</td>"+
        "<td>"+obj[prop]+"</td>"+
        "<td>Icon</td>"+
        "</tr>"+
    "</table>"
}

msg.html = html
return msg;

The "code" inside your ui_template node is sent to the dashboard for rendering, and since the node-red dashboard is an Angular v1.x app, you will be able to do a lot of conditional rendering logic -- once you understand the Ng directives (that's Angular's magic elements/attributes/syntax) that are available...

For example, this html <table> element can be conditionally rendered using the ng-if test to see if there are any rows to display:

<table ng-if="msg.payload.length">
  <caption class="nr-dashboard-color">Notification Logs</caption>
  <tr>
    <th>S.No</th>
    <th>Notification No.</th>
    <th>Date and Time</th>
    <th>Status</th>
    <th>Action</th>
  </tr>
  <tr ng-repeat="row in msg.payload">
    <td>{{$index+1}}</td>
    <td>{{row.notification}}</td>
    <td>{{row.timestamp}}</td>
    <td>{{row.status}}</td>
    <td>
      <button ng-click="send({payload: row.notification});"
              ng-if="row.status!=='success'">Retry</button>
    </td>
  </tr>
</table>

Notice also the use of ng-repeat to iterate over the payload data array, and the ng-if on the <button> element in the last column of the table. This way, the button only appears when that row has a status not equal to "success".

Finally, I use the ng-click attribute on the button to get access to the Ng scope, which has the send(...) method defined for returning data to the node-red flow downstream from my ui_template node. In this example I am just sending the Notifaction No. back as the msg.payload -- but if you used ng-click="send({ payload: row });" it would return the entire row as an object.

Once you fall down this rabbit hole of client-side logic and control, trust me you will no longer want to spend a bunch of time trying to build up your html page programatically! I still use the core template node in mustache mode to do some simple variable substitution and array expansion, but Angular is much more powerful a solution for a use case like yours.

shrickus, thank you sir!

I can show or hide the table based on a payload being present, eg:

<table ng-if="msg.payload.show">
</table>

In the function before the template I simply have:

msg.payload.show = 'yes';

If the above is not set, the table does not show.

problem solved!

1 Like

:sigh: this was what I was trying to get you to think about in the first place Ben.

Interestingly, I've come across a different but related problem that I couldn't solve with any combination of templates. That's because I have an object who's primary properties are arrays of objects. I wanted to output to a single table (multiple tables would have been trivial with the Dashboard template).

Of course, the answer was similar to the one that Steve suggests here - do the processing on the front-end rather than the back. In my case, I immediately gave up on Dashboard as I don't need any of its features so it was just getting in the way.