Node ui-builder

Hello everyone!

I've seen that there are very kind people in this forum and I've been encouraged to write my problems with UI bUilder :slight_smile:

I'm new to UI Builder and I had some problems.

What I want is a button that, if the user clicks on it, the typical "loading" logo appears and finally tells the user if the action has been performed or not.

image

For the back end (sending the action, checking that it has been sent correctly, etc.) I already had a subflow made and I would like to reuse it. This sends the action to the corresponding actuator, and thanks to debug4, I know through a msg if the action has been performed or not.
image
What I'm experiencing is that in the ui-builder node, in the front, I have to trigger the "showLoading()" function in the onclick to show to the user the typical "loading" drawing, but I want that, depending on whether the action has been performed or not, the "Action performed correctly" or "Action not performed correctly" function is triggered (which is normally done in javascript), with its corresponding display. But I only know that information about whether the action has been performed correctly through debug 4 that the flow offers me. Is it possible to obtain after X time, the value of a node-red global variable or pass that msg to the "uiBuilder" node so that it has the information? It's the only thing I've thought of so far.

Any recommendations are welcome!

Greetings and thanks!

Hi and welcome to the forum.

The 1st thing to note when using UIBUILDER or one of the Dashboards is that what happens in the client browser is an entirely separate computing context than what happens in Node-RED. The core of UIBUILDER is to provide a 2-way data link between Node-RED and connected browser clients.

So, to enable some event in Node-RED to update a connected client, you need to start by sending some data to the uibuilder node when that Node-RED event triggers a message flow.

Once you have events flowing into the connected client(s), you can program the client to do something based on the event data.


From what I understand of what you've described, you want to display a button to connected clients that, when pressed, triggers a flow in Node-RED that results in the user seeing something that confirms that the flow has completed?

If so, you add a button to the web page that, when pressed, sends a message back to Node-RED. You connect a Node-RED flow to the top output of the uibuilder node to listen for and process that message. Once the Node-RED flow completes, you will send a new message back to the connected client via the uibuilder node's input port. The client code will then show the completed message.

If you can confirm whether I've mostly got that right, we can work through some different ways of achieving the details.


By the way, when sharing code, please share as text between triple backticks (you can use the </> button in the edit box header to put them in. It then means that people can better help you by grabbing and trying/altering the code if needed.

Hello @TotallyInformation !

Thank you very much for all the information and the quick reply! :slight_smile:

I will explain my problem better

My idea was that, on the "onClick" button in html, a function would be triggered. In this case it would be the following function (which shows the typical "loading" image):

<input type="checkbox" id="lunchRoomLightState" onclick="showLoadingVisuals();uibuilder.eventSend(event)" data-type = "eventSend">

And within this function, wait until it responds with how the action finished (OK or ERROR). And based on that responded value, trigger the function of whether it went well or if it went badly (these functions would be the typical ones that show the green box for X seconds to indicate that it went well, or red if it gave an error).

//in the onClick Toggle:
function showLoadingVisuals() {
    const modifyIndividualBase = document.querySelector(".modifyIndividualBase");
    const loadingIndividualDiv = document.querySelector(".loadingIndividualDiv");

    modifyIndividualBase.style.opacity = 0;
    loadingIndividualDiv.style.display = "flex";
    loadingIndividualDiv.style.opacity = 1;
    modifyIndividualBase.style.display = "none";

   //Wait for actuator response (this is the value that I do not know how to get. this value is in msg of "debug 4" too:

   // const resultActuator= await getResponseActuator() ;
  //if(resultActuator){
      // showCommandOK();
  // }else{
    //   showCommandError();
//    }
   
 
}

The problem I have is that I don't know how to obtain within the javascript, in the UI-Builder node, the value that I expect from "getResponseActuator()". That response that I expect, is the same as the one that "debug 4" sends, when the node-red subflow ends:

   //Wait for actuator response (this is the value that I do not know how to get. this value is in msg of "debug 4" too:

   // const resultActuator= await getResponseActuator() ;
  //if(resultActuator){
      // showCommandOK();
  // }else{
    //   showCommandError();
//    }

I have looked to see how to obtain that value within the JS of the ui-builder node. However, I can't find a way to get that value to transform one function or another.

Any recommendation is welcome!

Thank you so much! :slight_smile:

OK, we can simplify a bit. Now I know that you are OK using front-end JavaScript.

onclick is good for buttons. But for inputs, you probably want to use onchange? Then it doesn't matter how the checked property is changed.

Then you don't need to call both your function and the eventSend in the same handler. Simply adjust your loading function to send a message when you want it to. You can use uibuilder.send({....}) within your function to send a custom message back to Node-RED.

The final bit you are missing is the response from Node-RED. So you've sent a msg to Node-RED as the input changes. You handle the output from the top output port of the uibuilder node and do whatever you need to do. Then at the end of that flow, you send a msg back to the uibuilder node (maybe use the link in/out nodes to keep your flow neat visually). That message needs to be tagged with something that your front-end JavaScript can recognise. The easy way is to give it a specific msg.topic. Then you can add this to your front-end JavaScript:

uibuilder.onTopic('mytopicname', (msg) => {
  // Call a function here to hide the visuals again - or do whatever needs doing.
}

Now you have 2-way data exchange between Node-RED and any connected client browser tabs.

If you don't want to use msg.topic for some reason, you can use uibuilder.onChange('msg', (msg) => { ... }) instead but you will then need some kind of if statement inside that callback to make sure you process the right message(s) in the right way.

Something Similar I got to working with Julian's Help.

button-uib

2 Likes

Thank you very much @TotallyInformation !

I have used "topic" and now I receive the msg correctly in the javascript front end :slight_smile:

Now, I am having another problem related to the checkbox.

As I show before, my flow is the next:

When I click above the checkbox, it changes to the other status:
image

Moreover, in the onchange of the checkbox, I trigger a function and I send an msg. This msg contains in this case (debug 1) value = true and checked = true (which is correct!):
image

Into the node "function 1" I just put the "area" and "actionToDo" in a msg depending on the "msg.payload.checked" for create the parameters to my subflow.

if(msg.payload.checked = true){
    msg.actionActuator = "OnLight";
    msg.area = msg._ui.id.replace(/LightState$/, "");
}

if(msg.payload.checked = false){
    msg.actionActuator = "OffLight";
    msg.area = msg._ui.id.replace(/LightState$/, "");
}
    return msg;

So, in this case, the action to do is "On" (look at debug 3):
image

As we can see, in the turningOn is everything OK, but the problem is in the turning off.

In the turning off:
In the debug 1 it is ok, because it is sending value = false and checked = false:
image

But in the debug 3, we can see that it always get "actionActuator" equal to "On", despite value and checked is false:
image

I do not understand what is happening.

Could please anyone help me?

Thank you so much! :slight_smile:

That is invalid JavaScript. The if statements need to be: if (msg.payload.checked === false) {

In other words, you need === which is an exact test rather than = which is an assignment. So currently your first if statement always sets the value to true.

Oh my God! What a basic mistake, thank you so much @TotallyInformation !