Messages IN/OUT template node - angular mustache syntax

Hello!

I'm currently using dashboards generated by ui_template node, displaying different data and getting messages from dashboard buttons.

The syntax I use for displaying data as example:
{{msg.time}} ... {{msg.date}} ... as placeholder in HTML file.
The buttons feedback messages are sent out directly from HTML as well:
ng-click="send({payload: 'main'})"

I want to migrate my dashboard to a HTML page in template node that uses mustache syntax.
Sending data to the dashboard page is not a problem using similar syntax {{time}} ... {{date}}.

I cant manage to send buttons messages directly from HTML page using the angular format.
my buttons are SVG

    <rect class="md-button" ng-click="send({payload: 'main'})"
      style="opacity:0.2;fill:#484b4b;fill-opacity:0.00392157;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
      id="button3" width="105.47041" height="52.678501" x="251.58435" y="16.125238" rx="7.3898969" ry="6.8063173" />

Is there any way to achieve this?

Thanks in advance!

1 Like

You would need to include a client side script in the html (for the send functionality). That function would need to make a POST request back to node-red. Lastly, you would need to add http endpoint (http-in node) to receive the POST requests.

Edit.

Also, ng-click is an angular thing. You'd need to use standard html attributes for Click events

Thanks for your replay.

I was trying to simplify as much as possible sending messages from HTML (avoiding to use script code if possible) and also to not re-code my dashboard HTML when migrate.
It is possible to add angular functionalities to HTML (template node) ?

Not without some kind of script. For example, you could include angularjs (and all the initialisation code / hook up, etc)- in which case, stick with dashboard!

However, you could also have a script that converts an ng-click attributes into regular click handlers

<script>
const ngClickElements = document.querySelectorAll('[ng-click]');

ngClickElements.forEach(element => {
    if (element.attributes['ng-click'].value) {
        element.setAttribute('onclick', element.attributes['ng-click'].value);
    }
});
</script>

And you would still need to create a function for the send

Something like:

<script>
async function send(data) {
    // If a non-object is passed, wrap it in an object under the 'payload' property
    const payload = typeof data === 'object' ? data : { payload: data };

    try {
        const response = await fetch('your_node-red_endpoint', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify(payload),
        });

        if (!response.ok) {
            throw new Error(`HTTP error! Status: ${response.status}`);
        }

        const responseData = await response.json();
        console.log('Response from backend:', responseData);
    } catch (error) {
        console.error('Error sending data to backend:', error.message);
    }
}
</script>

Lastly, you should probably wrap that in an IIFE or listen to DOMContentLoaded event

Here is (an untested example) script, in full, that you could include in your NON dashboard HTML:


(function() {
async function send(data) {
    const payload = typeof data === 'object' ? data : { payload: data };

    try {
        const response = await fetch('your/node-red/endpoint', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify(payload),
        });

        if (!response.ok) {
            throw new Error(`HTTP error! Status: ${response.status}`);
        }
    } catch (error) {
        console.error('Error sending data to backend:', error.message);
    }
}

const ngClickElements = document.querySelectorAll('[ng-click]');

ngClickElements.forEach(element => {
    if (element.attributes['ng-click'].value) {
        element.setAttribute('onclick', element.attributes['ng-click'].value);
    }
});
})();

DISCLAIMER: all untested / off the top of my head

2 Likes

Hello again,

I decide to try a different approach, and to use websocket to pass data the dashboard ...
Now, the message received is in this format:

Object { data101: "17:00", data102: "18:00", data103: "19:00", data104: "20:00", data105: "Wed", data106: "Thu", data107: "Fri", data108: "Sat", data201: "-1.2°C", data202: "-0.9°C", … }

to update the dashboard I use this script:

function updateSensorReadings(jsonResponse) {

  console.log(jsonResponse);

  document.getElementById('time').innerHTML = jsonResponse.time;
  document.getElementById('date').innerHTML = jsonResponse.date; 
  document.getElementById('sunset').innerHTML = jsonResponse.sunset;
  document.getElementById('sunrise').innerHTML = jsonResponse.sunrise;
  document.getElementById('wtemp').innerHTML = jsonResponse.wtemp;
  document.getElementById('whumid').innerHTML = jsonResponse.whumid;
  document.getElementById('pressure').innerHTML = jsonResponse.pressure;
  document.getElementById('data101').innerHTML = jsonResponse.data101; 
  document.getElementById('data102').innerHTML = jsonResponse.data102;
  document.getElementById('data103').innerHTML = jsonResponse.data103; 
  document.getElementById('data104').innerHTML = jsonResponse.data104;
  document.getElementById('data105').innerHTML = jsonResponse.data105; 
  document.getElementById('data106').innerHTML = jsonResponse.data106;
  document.getElementById('data107').innerHTML = jsonResponse.data107; 
  document.getElementById('data108').innerHTML = jsonResponse.data108; 
  document.getElementById('data201').innerHTML = jsonResponse.data201; 
  document.getElementById('data202').innerHTML = jsonResponse.data202;
  document.getElementById('data203').innerHTML = jsonResponse.data203; 
  document.getElementById('data204').innerHTML = jsonResponse.data204;
  document.getElementById('data205').innerHTML = jsonResponse.data205; 
  document.getElementById('data206').innerHTML = jsonResponse.data206;
  document.getElementById('data207').innerHTML = jsonResponse.data207; 
  document.getElementById(data208').innerHTML = jsonResponse.data208;  
}

I use same names for elements IDs and for payload object ... is there any way to simplify this function, to use a king of loop?

Thanks in advance for your time.
Lucian

Yes.

Object.keys() will give you an array of property names.

You can iterate them like this

const keys = Object.keys(jsonResponse)
for (let key of keys) {
  document.getElementById(key).innerHTML = jsonResponse[key]
}

NOTE: There is no error checking (you should check document.getElementById(key) is something before trying to set .innerHTML

Also, since this is dashboard1, i would probably say use jQuery

e.g.

const keys = Object.keys(jsonResponse)
for (let key of keys) {
  $('#' + key).html(jsonResponse[key])
}

^ that doesnt need any error checking


Disclaimer: all completely untested & nor proof read (expect typos or mistakes)


EDIT: See I said there may be errors - this is not using dashboard (so no jQuery right?)

1 Like

For my site (I name it dashboard) I use the template node not ui_template node.

Thanks again.

This is my weather dashboard

Your code works well also passing attributes too.

function updateSensorReadings(jsonResponse) {

  console.log(jsonResponse);

const keys = Object.keys(jsonResponse)
for (let key of keys) {
  document.getElementById(key).innerHTML = jsonResponse[key]
  document.getElementById(key).setAttribute("href", "/static"+jsonResponse[key]);
}

Much appreciate your help.

@lucibuz lovely dashboard! You should think about sharing your project (in the Share Your Projects section of the forum) so others could copy it and benefit from it!

1 Like

One more question.

I have multiple pages and some of the elements are repetitive, like time and date,
I have to use unique IDs to define the elements, and if one ID is duplicate just the first element with that ID will be updated ...
What is the best practice to update value of two elements with the 'same' ID?

Thanks,
Yes, for sure I'll do it.

I didn't do it yet because my code is not the best and defensively can be refined.
But hopefully other community members will help improve it :slight_smile: .

NEVER have duplicate IDs

1 Like

You had better wrap up warm then :cold_face:

hi @lucibuz

I know this is not going to help you ...
.. I've got distracted by the dashboard!
I didn't know we can do that in node-red.
Would you be kind to give some bullet pointed hints of what should I look into to create such dashboard as yours?
I was thinking of using ui_builder nodes ... but not there yet.

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.