Capture user data and Post to server as response

#1

Not sure if I titled it right, but I need to capture 2 values from a user at say:

http://localhost:1880/entervalues/

and then post them and parse them and display them. So far I know I need:

http-in node
function or template node
http response node

Ive worked with forms before but Im getting confused as to where to put what. Im also new to node-red btw.

I've made http-in node with url = /entervalues and set action to Post. I then added the template node and I was thinking of adding this code:

    <form id="idform">
        <div>
            <span>
                <input type="text" name="var1" id="var1" />
            </span>
            <span>
                <input type="text" name="var2" id="var2" />
            </span>
            <span>
                <input type="submit" value="Submit" id="idsubmit" />
            </span>
        </div>
    </form>

but then I dont know where to post to?

And I know I have to get the values like this in a function node and pass them to the http-response node:

var var1 = msg.req.query.var1;
var var2 = msg.req.query.var2;
msg.payload = parseInt(var1) + parseInt(var2);
return msg;

Im confused with the post flow because normally one html page (form.html) posts to another page (results.html).

#2

take a look at the cookbook page https://cookbook.nodered.org/http/post-form-data-to-a-flow

#3

Yeah thanks I saw it but I'm not able to make sense of it. Where does the data gathering code go (form html)?

The http-in node is set to post action and the url is url of the form itself or where the form will post to?

#4

The HTTP-In node is used to define an HTTP endpoint that will accept incoming requests. In this instance, you want one listening to POST requests to a url, for example /submitvalues.

Your HTML form can them be setup with:

<form action="/submitvalues" method="post">

so when the form is submitted, it will send the values as a POST request to /submitvalues.

#5

Your html <form> element needs to point to the url for your node-red http endpoint -- such as the one named /entervalues above.

#6

Thanks,

I did read the cookbook example, but I didnt understand it at all. Let me understand this piece by piece:

  1. First I need to create an http-in node
  2. Then that node connects to a template node that will contain the form-code in html
  3. Finally I connect the template node to an http-response node

Is this sequence correct?

#7

That sounds like the correct sequence to render the input form page -- i guess you serve that from the url /entervalues, right? Then let's say on your <form> element you have the submit url set to /submitvalues.

So then you need another flow starting with an http in node listening on url /submitvalues -- then whatever the form submits should end up in the msg.req.xxx properties (not sure if it's params, query, formdata, wth). You'll have to check by sending that msg to a debug node configured to show the "complete msg object". Drill down in the debug sidebar, and you should have your data. And don't forget to return at least a status code 200 ok through an http response node...

#8

ok i got it. Turns out I have to add a second http-in node to get the data from the first one. I set up one http-in as GET and another http-in as POST, both with the same /url. Then in the template use that /url

#9

Ok so now I have this setup:


and I get the values in the debug (as msg.payload)

Now I want to take the data from that and process it in a function, so I added a function node with this code:

var var1 = msg.payload.var1;
var var2 = msg.payload.var2;
msg.payload = parseInt(var1) + parseInt(var2);
return msg;

but I get a NaN error when loading /entervalues because they are not defined. How do I handle this? I want to process the 2 values before returning an http-response.

#10

Well, the picture does not show any inputs to the function node, so there should be no errors :*) But if it were to run with the debug objects shown, it looks like it would work. You are only wiring it into the POST flow, right?

While that picture is helpful, it doesn't really match up with your description of the problem you are still having. Perhaps if you export and post your flow json we could be more helpful... just remember to format the string as code by adding a line with 3 backtics (```) before AND after your flow.

Once you do get it working, you may want to add some defensive coding practices to avoid returning a NaN value. For instance, what do you plan to return if either var1 or var2 is missing or a non-numeric string? Since this is an http flow, it might be logical to return a 500 error -- or you could generate a different html page with the error embedded in it.

#11

Ok here is the code:

[{"id":"80051215.ef4dd","type":"template","z":"639706bc.6cfaa8","name":"Basic Html","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<html>\n <head></head>\n <body>\n <div id=\"idhello\"><span id=\"idnameout\"></span></div>\n <form id=\"idform\" action=\"/entervalues\" method=\"post\">\n <div>\n <span>\n <input type=\"text\" name=\"var1\" id=\"var1\" />\n </span>\n <span>\n <input type=\"text\" name=\"var2\" id=\"var2\" />\n </span>\n <span>\n <input type=\"submit\" value=\"Submit\" id=\"idsubmit\" />\n </span>\n </div>\n </form>\n <script src=\"//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js\">\n </script>\n <script type=\"text/javascript\">\n $(document).ready(function() {\n $('#idhello').hide();\n $('#idform').submit(onSubmitClicked);\n });\n \n function onSubmitClicked(event){\n $('#idnameout').text($('#var1').val())\n $('#idnameout').text($('#var2').val())\n $('#idhello').show();\n $('idform').hide();\n }\n </script>\n </body>\n </html>\n","output":"str","x":350,"y":280,"wires":[["dc76e700.613f38","cb8d1fdf.b9a42"]]},{"id":"e09c7711.805f78","type":"http in","z":"639706bc.6cfaa8","name":"[get] /entervalues","url":"/entervalues","method":"get","upload":false,"swaggerDoc":"","x":140,"y":280,"wires":[["80051215.ef4dd"]]},{"id":"dc76e700.613f38","type":"http response","z":"639706bc.6cfaa8","name":"Show values","statusCode":"","headers":{"content-type":"text/html"},"x":710,"y":280,"wires":[]},{"id":"cb8d1fdf.b9a42","type":"function","z":"639706bc.6cfaa8","name":"Showing Vars","func":"var var1 = \"0\" \nvar1 = msg.payload.var1;\nvar2 = \"0\"\nvar2 = msg.payload.var2;\nmsg.payload = parseInt(var1) + parseInt(var2);\nreturn msg;","outputs":1,"noerr":0,"x":540,"y":160,"wires":[["dc76e700.613f38"]]},{"id":"bc142ba3.40fb28","type":"http in","z":"639706bc.6cfaa8","name":"[post] /entervalues","url":"/entervalues","method":"post","upload":false,"swaggerDoc":"","x":150,"y":380,"wires":[["d4cd5ddb.2a993","a357258c.4c9698"]]},{"id":"a357258c.4c9698","type":"debug","z":"639706bc.6cfaa8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":470,"y":420,"wires":[]},{"id":"d4cd5ddb.2a993","type":"template","z":"639706bc.6cfaa8","name":"thanks","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<html> \n <head>\n </head>\n <body>\n <h1>Thanks for signing up!</h1>\n <p>You're all set.</p>\n </body>\n</html> ","output":"str","x":450,"y":340,"wires":[["c34be0da.3c051"]]},{"id":"c34be0da.3c051","type":"http response","z":"639706bc.6cfaa8","name":"","statusCode":"","headers":{},"x":690,"y":340,"wires":[]}]

#12

As I expected, you have the function node wired into the GET flow (which generates the input page), rather than the POST flow (which processes the values).

#13

OK I re-wired it and here is the code and what it looks like, but I think my coding is off. Would I need to grab those variables in the thanks:template node and then pass them to the http-response? How would I do that?

[{"id":"1998340e.de7cac","type":"tab","label":"Flow 2","disabled":false,"info":""},{"id":"df653799.3afa78","type":"template","z":"1998340e.de7cac","name":"Basic Html","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<html>\n <head></head>\n <body>\n <div id=\"idhello\"><span id=\"idnameout\"></span></div>\n <form id=\"idform\" action=\"/entervalues\" method=\"post\">\n <div>\n <span>\n <input type=\"text\" name=\"var1\" id=\"var1\" />\n </span>\n <span>\n <input type=\"text\" name=\"var2\" id=\"var2\" />\n </span>\n <span>\n <input type=\"submit\" value=\"Submit\" id=\"idsubmit\" />\n </span>\n </div>\n </form>\n <script src=\"//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js\">\n </script>\n <script type=\"text/javascript\">\n $(document).ready(function() {\n $('#idhello').hide();\n $('#idform').submit(onSubmitClicked);\n });\n \n function onSubmitClicked(event){\n $('#idnameout').text($('#var1').val())\n $('#idnameout').text($('#var2').val())\n $('#idhello').show();\n $('idform').hide();\n }\n </script>\n </body>\n </html>\n","output":"str","x":330,"y":120,"wires":[["f060a4d.531fd58"]]},{"id":"49cbd6fb.37f168","type":"http in","z":"1998340e.de7cac","name":"[get] /entervalues","url":"/entervalues","method":"get","upload":false,"swaggerDoc":"","x":120,"y":120,"wires":[["df653799.3afa78"]]},{"id":"f060a4d.531fd58","type":"http response","z":"1998340e.de7cac","name":"Show values","statusCode":"","headers":{"content-type":"text/html"},"x":690,"y":120,"wires":[]},{"id":"a6b3a7c8.f1e278","type":"function","z":"1998340e.de7cac","name":"Showing Vars","func":"var var1 = \"0\" \nvar1 = msg.payload.var1;\nvar2 = \"0\"\nvar2 = msg.payload.var2;\nmsg.payload = parseInt(var1) + parseInt(var2);\nreturn msg;","outputs":1,"noerr":0,"x":580,"y":180,"wires":[["dd7e991b.d2bb78"]]},{"id":"a45efa52.778328","type":"http in","z":"1998340e.de7cac","name":"[post] /entervalues","url":"/entervalues","method":"post","upload":false,"swaggerDoc":"","x":130,"y":320,"wires":[["a8f46593.1f57f8","5ce2b0b6.b4501"]]},{"id":"5ce2b0b6.b4501","type":"debug","z":"1998340e.de7cac","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":450,"y":360,"wires":[]},{"id":"a8f46593.1f57f8","type":"template","z":"1998340e.de7cac","name":"thanks","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<html> \n <head>\n </head>\n <body>\n <h1>Thanks for signing up!</h1>\n <p>You're all set.</p>\n </body>\n</html> ","output":"str","x":370,"y":280,"wires":[["dd7e991b.d2bb78","a6b3a7c8.f1e278"]]},{"id":"dd7e991b.d2bb78","type":"http response","z":"1998340e.de7cac","name":"","statusCode":"","headers":{},"x":790,"y":280,"wires":[]}]

#14

Put debug nodes everywhere.

#15

Here is the result:

  1. The first debug node (from post) is 81....and it got the msg.payload Object var1 and var2 with its values.
  2. The debug node from thanks template f0f....got the thank you string.
  3. The debug node from function node 2db....got Nan
  4. Oh, the last one on the bottom 5ce....is a duplicate really. Im just realizing how to recognize each node :slight_smile:
  5. And I cant attach one to the http-response, but its returning an error where the headers cannot be changed once they are sent.

Ok so the issue is that the thanks node isnt getting the values from the post node, so my question is, how do I add them to that template node? I know how to add them to a function node, using the code in the Showing vars function node, but I dont know how to add the variables to the thanks template node.

Or should the function node go before the thanks node?

#16

if you change the name of the debugnodes in the debug config window it makes it a lot easier…

You are getting the “can’t set headers” error because 1 message from the http in node results in 2 messages to the http out node (1 via the direct path and the other via the function node)

#17

Yes because if I eliminate the direct link from thanks to http-response I get just the NaN error when I post

#18

the NaN is because you are trying to do something with (i’m guessing) msg.payload as if it is a number. but it’s not so you get NaN (not a number)

#19

Ok so Ive made some advances. Im using this in the function node:

var var1 = msg.payload.var1;
var var2 = msg.payload.var2;
msg.payload.result = parseInt(var1) + parseInt(var2);
return msg;

but Im not able to get the msg.payload.result the downstream debug node.

#20

What are you doing in the node that passes the msg to the function node?????