Ajax form file upload - catch file write error

I found a flow created by Nick using Ajax form for uploading files. I have modified it to write to the filesystem and it works great. I want to be able to pass the success or fail from the file write node back to the form popup message. The flow gives me this message which I realized only looks at the template results and not the write node.

image

In the above case the file write failed due to incorrect file path. I am using a catch node to dump the output to context.
image

How can I parse the context data and inserted into the a success or fail object within the Ajax call.

See flow below

image

[{"id":"b8284e52a98d6edf","type":"group","z":"1370cad3dea7d005","name":"Upload File Template","style":{"label":true},"nodes":["1a5eaffe20d55f62","badef399114c7186","53fe6b3b72822a78","39575309ba1a1ebd","446de8c01dc5aa65","3686c1606299e93c","581e9356067885c4","38a4d739d196aa75","073bfdd2b72907ab","1cfed2d982d8b591","d9c54a5756141e3a"],"x":14,"y":19,"w":412,"h":282},{"id":"1a5eaffe20d55f62","type":"http in","z":"1370cad3dea7d005","g":"b8284e52a98d6edf","name":"","url":"/file-upload","method":"post","upload":true,"swaggerDoc":"","x":120,"y":180,"wires":[["53fe6b3b72822a78","badef399114c7186","3686c1606299e93c"]]},{"id":"badef399114c7186","type":"debug","z":"1370cad3dea7d005","g":"b8284e52a98d6edf","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"req.files","targetType":"msg","statusVal":"","statusType":"auto","x":310,"y":180,"wires":[]},{"id":"53fe6b3b72822a78","type":"function","z":"1370cad3dea7d005","g":"b8284e52a98d6edf","name":"","func":"msg.payload = \"OK\";\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":140,"y":220,"wires":[["39575309ba1a1ebd"]]},{"id":"39575309ba1a1ebd","type":"http response","z":"1370cad3dea7d005","g":"b8284e52a98d6edf","name":"","statusCode":"","headers":{},"x":290,"y":220,"wires":[]},{"id":"446de8c01dc5aa65","type":"file","z":"1370cad3dea7d005","g":"b8284e52a98d6edf","name":"writeFile","filename":"filename","filenameType":"msg","appendNewline":false,"createDir":false,"overwriteFile":"true","encoding":"setbymsg","x":300,"y":140,"wires":[[]]},{"id":"3686c1606299e93c","type":"function","z":"1370cad3dea7d005","g":"b8284e52a98d6edf","name":"formatFile","func":"msg = { payload: msg.req.files[0].buffer, filename: '/home/pi'+msg.req.files[0].originalname}\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":140,"y":140,"wires":[["446de8c01dc5aa65"]]},{"id":"581e9356067885c4","type":"ui_template","z":"1370cad3dea7d005","g":"b8284e52a98d6edf","group":"c1de91543c517b44","name":"css","order":1,"width":0,"height":0,"format":"<style>\nlabel, input {\ndisplay: block;\ncolor: #808080;\n}\nlabel {\nmargin-bottom: 10px;\n}\n</style>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","className":"","x":150,"y":100,"wires":[[]]},{"id":"38a4d739d196aa75","type":"comment","z":"1370cad3dea7d005","g":"b8284e52a98d6edf","name":"ReadMe","info":"# Simple Input form to load file from node red dashboard to server\n## Flow automatically picks up file name and msg encoding\n## Default upload location is /home/pi \n - Edit formatFile function to change location\n","x":220,"y":60,"wires":[]},{"id":"073bfdd2b72907ab","type":"ui_template","z":"1370cad3dea7d005","g":"b8284e52a98d6edf","group":"c1de91543c517b44","name":"form","order":5,"width":"6","height":"2","format":"<form id=\"myForm\">\n  <label>\n    <input id=\"myFile\" type=\"file\" name=\"fileToUpload\">\n    </label>\n  <label>\n    <input type=\"submit\" value=\"Upload File\" name=\"submit\">\n    </label>\n</form>\n<script>\n  $('#myForm').submit(function(e) {\n        e.preventDefault();\n        var fd = new FormData();    \n        fd.append( 'file', $('#myFile')[0].files[0] );\n\n  $.ajax({\n    url: '/file-upload',\n    data: fd,\n    processData: false,\n    contentType: false,\n    type: 'POST',\n    success: function(data){\n      alert('Ok');\n      $(\"#myForm\")[0].reset();\n      }\n    });\n  });\n</script>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","className":"","x":290,"y":100,"wires":[[]]},{"id":"1cfed2d982d8b591","type":"catch","z":"1370cad3dea7d005","g":"b8284e52a98d6edf","name":"","scope":["446de8c01dc5aa65"],"uncaught":false,"x":150,"y":260,"wires":[["d9c54a5756141e3a"]]},{"id":"d9c54a5756141e3a","type":"function","z":"1370cad3dea7d005","g":"b8284e52a98d6edf","name":"function 1","func":"var error = flow.set(\"error\", msg.error)\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":300,"y":260,"wires":[[]]},{"id":"c1de91543c517b44","type":"ui_group","name":"Upload Files","tab":"f5bc4cdce2c30720","order":1,"disp":true,"width":"6","collapse":false,"className":""},{"id":"f5bc4cdce2c30720","type":"ui_tab","name":"Home","icon":"dashboard","disabled":false,"hidden":false}]

The success and error is done in the ui-template and the catch node needs to be joined and if error is present send status code 500 for error response
e.g.

[{"id":"1a5eaffe20d55f62","type":"http in","z":"d58a0e9fb6feb9d6","name":"","url":"/file-upload","method":"post","upload":true,"swaggerDoc":"","x":140,"y":1140,"wires":[["badef399114c7186","3686c1606299e93c","a70c076ce9471b62"]]},{"id":"badef399114c7186","type":"debug","z":"d58a0e9fb6feb9d6","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"req.files","targetType":"msg","statusVal":"","statusType":"auto","x":210,"y":1080,"wires":[]},{"id":"3686c1606299e93c","type":"function","z":"d58a0e9fb6feb9d6","name":"formatFile","func":"msg = { payload: msg.req.files[0].buffer, topic: \"write\", filename: '/home/pi'+msg.req.files[0].originalname}\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":360,"y":1120,"wires":[["446de8c01dc5aa65"]]},{"id":"a70c076ce9471b62","type":"change","z":"d58a0e9fb6feb9d6","name":"","rules":[{"t":"set","p":"topic","pt":"msg","to":"res","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":280,"y":1200,"wires":[["9ef6339d4ba52b16"]]},{"id":"446de8c01dc5aa65","type":"file","z":"d58a0e9fb6feb9d6","name":"writeFile","filename":"filename","filenameType":"msg","appendNewline":false,"createDir":false,"overwriteFile":"true","encoding":"setbymsg","x":520,"y":1120,"wires":[["9ef6339d4ba52b16"]]},{"id":"9ef6339d4ba52b16","type":"join","z":"d58a0e9fb6feb9d6","name":"","mode":"custom","build":"object","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":false,"timeout":"","count":"2","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":490,"y":1200,"wires":[["0f7d00e07dfb9794","24ce2c4bda306c7e"]]},{"id":"6e620ad4c4cdeee7","type":"change","z":"d58a0e9fb6feb9d6","name":"","rules":[{"t":"set","p":"topic","pt":"msg","to":"write","tot":"str"},{"t":"set","p":"payload","pt":"msg","to":"error.message","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":280,"y":1280,"wires":[["9ef6339d4ba52b16"]]},{"id":"0f7d00e07dfb9794","type":"debug","z":"d58a0e9fb6feb9d6","name":"debug 311","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":690,"y":1160,"wires":[]},{"id":"24ce2c4bda306c7e","type":"function","z":"d58a0e9fb6feb9d6","name":"function 27","func":"if(msg.error){\n    msg.statusCode=500;\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":650,"y":1200,"wires":[["39575309ba1a1ebd"]]},{"id":"e781fb11f8ea24f4","type":"catch","z":"d58a0e9fb6feb9d6","name":"","scope":["446de8c01dc5aa65"],"uncaught":false,"x":130,"y":1280,"wires":[["6e620ad4c4cdeee7"]]},{"id":"39575309ba1a1ebd","type":"http response","z":"d58a0e9fb6feb9d6","name":"","statusCode":"","headers":{},"x":790,"y":1200,"wires":[]},{"id":"581e9356067885c4","type":"ui_template","z":"d58a0e9fb6feb9d6","group":"c1de91543c517b44","name":"css","order":1,"width":0,"height":0,"format":"<style>\nlabel, input {\ndisplay: block;\ncolor: #808080;\n}\nlabel {\nmargin-bottom: 10px;\n}\n</style>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","className":"","x":370,"y":1080,"wires":[[]]},{"id":"073bfdd2b72907ab","type":"ui_template","z":"d58a0e9fb6feb9d6","group":"c1de91543c517b44","name":"form","order":5,"width":"6","height":"2","format":"<form id=\"myForm\">\n  <label>\n    <input id=\"myFile\" type=\"file\" name=\"fileToUpload\">\n    </label>\n  <label>\n    <input type=\"submit\" value=\"Upload File\" name=\"submit\">\n    </label>\n</form>\n<script>\n  $('#myForm').submit(function(e) {\n        e.preventDefault();\n        var fd = new FormData();    \n        fd.append( 'file', $('#myFile')[0].files[0] );\n\n  $.ajax({\n    url: '/file-upload',\n    data: fd,\n    processData: false,\n    contentType: false,\n    type: 'POST',\n    success: function(data){\n      alert('Ok');\n      $(\"#myForm\")[0].reset();\n      },\n    error: function(errMsg) {alert(errMsg.responseText)}\n    });\n  });\n</script>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","className":"","x":510,"y":1080,"wires":[[]]},{"id":"c1de91543c517b44","type":"ui_group","name":"Upload Files","tab":"f5bc4cdce2c30720","order":1,"disp":true,"width":"6","collapse":false,"className":""},{"id":"f5bc4cdce2c30720","type":"ui_tab","name":"Home","icon":"dashboard","disabled":false,"hidden":false}]

[edit] fixed file write filename as i removed for testing

Thank you sir

Is there a special setting required?

For me it does not show a message at all if upload and saving fails.

With your flow I get:
output_filesave_01

I had previously figured out how to catch the write error. I am storing the msg.error in context and fetching it in the Notify function node. Please note there is a little more code in this new flow as I am trying to get a spinner to work on upload. It fails but does not impact the core functions.

image

image

I also coded it to show if you fail to select a file

image

[{"id":"1370cad3dea7d005","type":"tab","label":"Upload File","disabled":false,"info":"","env":[]},{"id":"b8284e52a98d6edf","type":"group","z":"1370cad3dea7d005","name":"Upload File Template","style":{"label":true},"nodes":["1a5eaffe20d55f62","53fe6b3b72822a78","39575309ba1a1ebd","446de8c01dc5aa65","3686c1606299e93c","581e9356067885c4","38a4d739d196aa75","073bfdd2b72907ab","1cfed2d982d8b591","6b932711ef1157e3"],"x":174,"y":19,"w":312,"h":282},{"id":"1a5eaffe20d55f62","type":"http in","z":"1370cad3dea7d005","g":"b8284e52a98d6edf","name":"Post","url":"/file-upload","method":"post","upload":true,"swaggerDoc":"","x":250,"y":180,"wires":[["3686c1606299e93c","53fe6b3b72822a78"]]},{"id":"53fe6b3b72822a78","type":"function","z":"1370cad3dea7d005","g":"b8284e52a98d6edf","name":"Notify","func":"    await new Promise(resolve => setTimeout(resolve, 2000));\n    if (flow.get(\"err_msg\") !== 'undefined') {\n        msg.payload = \"File Upload \" + flow.get(\"err_msg\");\n        node.send(msg);\n        flow.set(\"err_msg\",'undefined');\n        return;\n    }\n    if (flow.get(\"err_msg\") === 'undefined'){\n        msg.payload = \"File Uploaded\";\n        flow.set(\"err_msg\", 'undefined');\n        node.send(msg);\n    }","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":250,"y":220,"wires":[["39575309ba1a1ebd"]]},{"id":"39575309ba1a1ebd","type":"http response","z":"1370cad3dea7d005","g":"b8284e52a98d6edf","name":"","statusCode":"","headers":{},"x":390,"y":220,"wires":[]},{"id":"446de8c01dc5aa65","type":"file","z":"1370cad3dea7d005","g":"b8284e52a98d6edf","name":"writeFile","filename":"filename","filenameType":"msg","appendNewline":false,"createDir":false,"overwriteFile":"true","encoding":"setbymsg","x":400,"y":140,"wires":[[]]},{"id":"3686c1606299e93c","type":"function","z":"1370cad3dea7d005","g":"b8284e52a98d6edf","name":"formatFile","func":"msg = { payload: msg.req.files[0].buffer, filename: '/home/pi/'+msg.req.files[0].originalname}\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":260,"y":140,"wires":[["446de8c01dc5aa65"]]},{"id":"073bfdd2b72907ab","type":"ui_template","z":"1370cad3dea7d005","g":"b8284e52a98d6edf","group":"c1de91543c517b44","name":"form","order":5,"width":"6","height":"2","format":"<body style=\"text-align: center;\">\n<form id=\"myForm\">\n   <label>\n    <input id=\"myFile\" type=\"file\"  name=\"fileToUpload\">\n    </label>\n  <label>\n    <input type=\"submit\" value=\"Upload File\" name=\"submit\">\n    </label>    \n</form> \n<div class=\"overlay\"></div>\n</body>\n<script>\n  $('#myForm').submit(function(e) {\n        e.preventDefault();\n        var fd = new FormData();    \n        fd.append( 'file', $('#myFile')[0].files[0] );\n  $.ajax({\n    url: '/file-upload',\n    data: fd,\n    processData: false,\n    contentType: false,\n    type: 'POST',\n    success: function(data){\n      alert(data);\n      $(\"#myForm\")[0].reset();\n      }\n    });\n  });\n  $('#myForm').on({\n  ajaxStart: function(){\n  $(\"body\").addClass(\"loading\");\n  },\n  ajaxStop: function(){\n  $(\"body\").removeClass(\"loading\");\n  }\n  }); \n</script>\n","storeOutMessages":false,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"local","className":"","x":390,"y":100,"wires":[[]]},{"id":"581e9356067885c4","type":"ui_template","z":"1370cad3dea7d005","g":"b8284e52a98d6edf","group":"c1de91543c517b44","name":"css","order":1,"width":0,"height":0,"format":"<style>\nlabel, input {\ndisplay: block;\ncolor: #808080;\n}\nlabel {\nmargin-bottom: 10px;\n}\n.overlay{\ndisplay: none;\nposition: fixed;\nwidth: 100%;\nheight: 100%;\ntop: 0;\nleft: 0;\nz-index: 999;\nbackground: rgba(255,255,255,0.8) url(\"loader.gif\") center no-repeat;\n}\n/* Turn off scrollbar when body element has the loading class */\nbody.loading{\noverflow: hidden;\n}\n/* Make spinner image visible when body element has the loading class */\nbody.loading .overlay{\ndisplay: block;\n}\n\n</style>","storeOutMessages":false,"fwdInMessages":false,"resendOnRefresh":false,"templateScope":"local","className":"","x":250,"y":100,"wires":[[]]},{"id":"38a4d739d196aa75","type":"comment","z":"1370cad3dea7d005","g":"b8284e52a98d6edf","name":"ReadMe","info":"# Ajax Input form to load file from dashboard UI to server file system\n## Flow automatically picks up file name and msg encoding\n---\n## Default upload location is **/home/pi** \n\n##  Edit **_formatFile_** function node to change location\n   `msg = { payload: msg.req.files[0].buffer, filename: '/home/pi/'+msg.req.files[0].originalname}`\n\n---\n## Error Checking on Upload and file system Write will output to pop up window.  There is a 2 second delay after pressing the upload file button before the pop up window will display\n   Successful Upload example: `File Uploaded`\n   \n   Invalid filesystem example: `File Upload failed to write to file: Error: ENOENT: no such file or directory, open C:\\home\\pi\\newsleter.sql`\n   \n   No file selected example: `File Upload TypeError: Cannot read properties of undefined (reading 'buffer')`","x":320,"y":60,"wires":[]},{"id":"1cfed2d982d8b591","type":"catch","z":"1370cad3dea7d005","g":"b8284e52a98d6edf","name":"catch","scope":["446de8c01dc5aa65","3686c1606299e93c"],"uncaught":false,"x":250,"y":260,"wires":[["6b932711ef1157e3"]]},{"id":"6b932711ef1157e3","type":"function","z":"1370cad3dea7d005","g":"b8284e52a98d6edf","name":"Error","func":"if (msg.error.message !== 'undefined') {\n    flow.set(\"err_msg\", msg.error.message)\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":390,"y":260,"wires":[[]]},{"id":"c1de91543c517b44","type":"ui_group","name":"Upload Files","tab":"f5bc4cdce2c30720","order":1,"disp":true,"width":"6","collapse":false,"className":""},{"id":"f5bc4cdce2c30720","type":"ui_tab","name":"Home","icon":"dashboard","disabled":false,"hidden":false}]

No special setting, is it my flow unedited?
Have you tried clearing browser cache?

Yes, your flow. I only changed the path as you can see in the gif.
Unaffected by browser cache.

I just tested E1cid flow and it worked fine. Try restarting node red to see if that will clear your issue.

image

The flow I posted this morning includes a error msg if you click upload when no file is selected and will send an error. Since I am using context I have a 2 sec wait built into the node to allow time to parse the context.

Hmmm, just tried your flow and it works, @E1cid's does not.
I'll try to figure out the difference...

Nevermind, I restarted the whole container and now it works. I have no idea why, but it works now. Thank you.

@Mick, if you get the progress wheel or similar to work, I would be interested in how you did it.

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