Working with Array of Strings

#1

Hi,

I'm trying to write an HTML site that will loop through images from a list of urls. Currently I have it set up that the file list (filenames.txt) is imported from my dropbox (I am running my instance on IBM so I don't have the file in node, this is my work-around). I then split the input into different messages, as on the node-red site (https://nodered.org/docs/writing-functions). I then feed this array of strings to my HTML with a loop refresh function that should refresh the page every 1000ms, each time going down the array of strings to display the next one down.

I have practised this with an array of numbers (msg.test), that works fine and easy. However, if I switch the input to the array with strings, it doesn't work. I think it is a matter of not defining my array of strings properly, because if I leave out the looping aspect and just try to display the entire array, I get [object Object].

How can I define that it is an array of strings? Or is it another issue and I'm just not seeing it?

Here is my flow:

[{"id":"671aa315.d9bbac","type":"http in","z":"93be8ca4.c31bb","name":"","url":"/rcg","method":"get","upload":false,"swaggerDoc":"","x":65,"y":1369,"wires":[["79f710f9.2b84d8"]]},{"id":"79f710f9.2b84d8","type":"dropbox","z":"93be8ca4.c31bb","dropbox":"","filename":"filenames.txt","name":"Filenames","x":288,"y":1428,"wires":[["6269fd0b.fdcac4"]]},{"id":"6269fd0b.fdcac4","type":"function","z":"93be8ca4.c31bb","name":"functions","func":"function array_range(start, len) \n {\n\t\tvar arr = new Array(len);\n\t\tfor (var i = 0; i < len; i++, start++) \n {\n\t\t\tarr[i] = start;\n\t\t}\n \t\treturn arr;\n}\n\nfunction shuffle(array) {\n var currentIndex = array.length, temporaryValue, randomIndex;\n\n // While there remain elements to shuffle...\n while (0 !== currentIndex) {\n\n // Pick a remaining element...\n randomIndex = Math.floor(Math.random() * currentIndex);\n currentIndex -= 1;\n\n // And swap it with the current element.\n temporaryValue = array[currentIndex];\n array[currentIndex] = array[randomIndex];\n array[randomIndex] = temporaryValue;\n }\n\n return array;\n}\n\nvar outputMsgs = [];\nvar words = msg.payload.split(\";\");\nfor (var w in words) {\n outputMsgs.push({payload:words[w]});\n}\n\nlength = outputMsgs.length;\n\nvar test = array_range(0,length);\ntest = shuffle(test);\n\nmsg.test = test;\nmsg.text = outputMsgs;\n\nreturn msg;","outputs":1,"noerr":0,"x":467.5,"y":1344,"wires":[["cd74ce58.325cf","81c71059.3723f8"]]},{"id":"cd74ce58.325cf","type":"debug","z":"93be8ca4.c31bb","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":647,"y":1452,"wires":[]},{"id":"81c71059.3723f8","type":"template","z":"93be8ca4.c31bb","name":"","field":"payload","fieldType":"msg","format":"html","syntax":"mustache","template":"<html>\n <head>\n <script>\n var refreshInterval = 1000;\n var i = 0;\n var input = new Array({{text}});\n \n function refresh()\n {\n setTimeout(\"refresh()\",refreshInterval);\n document.getElementById(\"loop\").innerHTML = input[i];\n i++\n }</script>\n </head>\n <body onload = 'refresh()'>\n <p id = \"loop\"></p>\n \n </body>\n</html>","output":"str","x":635.5,"y":1291,"wires":[["e9a7e662.b0a9e8"]]},{"id":"e9a7e662.b0a9e8","type":"http response","z":"93be8ca4.c31bb","name":"","statusCode":"","headers":{},"x":774.5,"y":1385,"wires":[]}]

Thanks for any help!

#2

Hi,

the mustache syntax used by the Template node will just do a toString of whatever msg.text holds, which, if it's an array, will result in [object Object].

The quick fix is to encode msg.text to a JSON string in your Function node - so the Template node just inserts its value as-is.

msg.text = JSON.stringify(outputMsgs);
#3

Thanks for the quick reply. However, that still hasn't made any difference. I still get [object Object] (x4). If I put {{{text}}} in the body, then it shows the whole array, but if I embed it in the refresh() script, I still get nothing. Maybe that is also a clue? Why would the script interpret it differently than if I "hardcode" it into the HTML body?

I assume once I can get the whole array displayed, I can then introduce the index to get it to loop through the array.

#4

Ok, if I define it as var input = new Array('{{text}}'); in the script section of the template node, then I can get the whole array to display via the refresh() function. However, how would I then navigate to a specific line? For example, ('{{text[0].payload}}') loads nothing, so that must not be pointing at the right place (although that is what I get when I use copy path from the debugger node.

#5

Hi,

I've figured it out! I discovered that it would be easier if I passed the msg.payload and split it in the template file than to split it in the function file and then pass over the array. However, in order for the template node to still be able to read it, I had to JSON.stringify the msg.payload. So I still wouldn't have figured out the answer without your help :slightly_smiling_face:

Thank you!