Multiple setTimeout/clearTimeout Within Same Function Node

I'm relatively new to Node Red and JavaScript in general, so am probably being extremely dense.

Basically, I'm trying to work out how to set a timer for one input, if it's false, and to cancel it if it's true, but for different topics. I know I can use delay nodes and have a different one for each output, but in the spirit of learning, I'd like to do all of this in a function node.

I can't seem to work out and I've searched everywhere, but obviously can't seem to take the information in properly, how to implement the clearTimer() properly. I've (hopefully) put in an example of a broken version of what I'd like to achieve, but if there's anything else you need to know to help you to help me, let me know.

As I say, I'm new to this, so apologies if I've missed anything blindingly obvious. This is just the latest example of attempts I've made, but hopefully it shows what I'm trying to do.

[{"id":"6f2380c6.3e333","type":"debug","z":"e374584c.a7eb58","name":"","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"true","targetType":"full","x":430,"y":640,"wires":[]},{"id":"8eaeb610.52eb58","type":"inject","z":"e374584c.a7eb58","name":"","topic":"roomname1","payload":"true","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":120,"y":640,"wires":[["2c603376.d5ba0c"]]},{"id":"65ea0449.f9a3dc","type":"inject","z":"e374584c.a7eb58","name":"","topic":"roomname1","payload":"false","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":120,"y":600,"wires":[["2c603376.d5ba0c"]]},{"id":"2c603376.d5ba0c","type":"function","z":"e374584c.a7eb58","name":"","func":"function timer () {\n    if (msg.payload == \"false\"){\n    node.send(msg)\n    }\n}\n\nif (msg.topic == \"roomname2\") {\n    var roomname2 = setTimeout(timer, 2000);\n    if (msg.payload == \"true\") {\n        clearTimeout(roomname2);\n    }\n}\n\nif (msg.topic == \"roomname1\") {\n    var roomname1 = setTimeout(timer, 3000);\n    if (msg.payload == \"true\") {\n        clearTimeout(roomname1);\n    }\n}","outputs":1,"noerr":0,"x":290,"y":640,"wires":[["6f2380c6.3e333"]]},{"id":"c0b887ef.6147a8","type":"inject","z":"e374584c.a7eb58","name":"","topic":"roomname2","payload":"true","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":120,"y":720,"wires":[["2c603376.d5ba0c"]]},{"id":"edfb349f.ae8468","type":"inject","z":"e374584c.a7eb58","name":"","topic":"roomname2","payload":"false","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":120,"y":680,"wires":[["2c603376.d5ba0c"]]}]

Not dense, it isn't obvious if you've not done it before.

The trick is to remember that a set timer returns a timer object reference. So you have to assign to a variable. Then you can track/clear multiple timers.

Still looking at your flow yet but that is the basics.

From your flow, you are not saving the timers to context so they will be created/lost on each incoming msg.


Since I had a few minutes and the excercise was good for me, here is a working example - note that you need to change your triggers to use boolean inputs rather than text.


function timer1 () {
    // This runs when the timer expires
    // msg is set to the incoming msg at the time the timer was created
    node.send(msg)
    node.warn('TIMER IS SELF CANCELLING FOR TOPIC ' + msg.topic )
    // Delete the entry from the context var and write back
    delete timers[msg.topic]
    context.set('timers', timers)
}

// Get the timers from the context store
let timers = context.get('timers') || {}

// Is there an existing timer for this topic?
if ( timers[msg.topic] ) {
    // If so, is the NEW payload TRUE?
    if ( msg.payload === true ) {
        // Cancel the timer & delete from context
        node.warn('CANCELLING TIMER FOR EXISTING TOPIC ' + msg.topic )
        clearTimeout(timers[msg.topic])
        delete timers[msg.topic]
    } else {
        // NEW payload is FALSE so create a timer
        // NB: timouts cancel themselves when they run
        node.warn('CREATING NEW TIMER FOR EXISTING TOPIC ' + msg.topic )
        timers[msg.topic] = setTimeout(timer1, 5000)
    }
} else {
    // Only interested in a payload of FALSE since 
    // there will be no timer to cancel in this case
    if ( msg.payload === false ) {
        // NEW payload is FALSE so create a timer
        // NB: timouts cancel themselves when they run
        node.warn('CREATING NEW TIMER FOR NEW TOPIC ' + msg.topic )
        timers[msg.topic] = setTimeout(timer1, 5000)
    }
}

// Update the timers to the context store
context.set('timers', timers)

You could refactor that code slightly to simplify the nested if's.

I also suspect that it would be possible to get race conditions with this code if you were sending through topics and cancelling them faster than the timeout value.

2 Likes

That's great. Thank you so much. I'm going to take what you've written and reverse engineer it (I seem to be able to work things out better that way.)

I think I just need to learn a bit more about saving incoming data via context.set, as that's the part that I couldn't quite work out. I thought that the "var ROOMNAME" was saving the data in the node, but was obviously wrong.

Thank you again.

Have a look in the node-red guide at the page on Writing Functions, that gives lots of useful information about everything to do with function nodes, including using the context stores.

2 Likes

Well, context/flow/global variables shouldn't be over-used. Best to stick with msg passing wherever possible but sometimes it is the only way. Obviously, you also need to watch out for saved vars getting too big so always make sure you are tidying them up like I did in the example.

Will do. It was more the having a changeable context based on the topic that's been confusing me. I can set and get stored data when naming the context myself, but just haven't been able to store it dynamically.

I suppose I'm maybe being a bit too ambitious to start off with, when I could just be using preexisting nodes, until I'm used to the more basic functions.

[{"id":"8e1afa9c.72c718","type":"tab","label":"Flow 1","disabled":false,"info":""},{"id":"74191c84.d19164","type":"mqtt out","z":"8e1afa9c.72c718","name":"","topic":"","qos":"0","retain":"true","broker":"2f3156fc.9fdc8a","x":570,"y":420,"wires":[]},{"id":"a6afd3e3.c88ca","type":"inject","z":"8e1afa9c.72c718","name":"","topic":"home/upstairs/hall/motion","payload":"true","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":180,"y":360,"wires":[["74191c84.d19164"]]},{"id":"e2cb9261.179d5","type":"inject","z":"8e1afa9c.72c718","name":"","topic":"home/upstairs/hall/motion","payload":"false","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":190,"y":400,"wires":[["74191c84.d19164"]]},{"id":"a113d9cb.4e60a8","type":"inject","z":"8e1afa9c.72c718","name":"","topic":"home/upstairs/office/motion","payload":"true","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":190,"y":440,"wires":[["74191c84.d19164"]]},{"id":"3fb7c4f9.9fa55c","type":"inject","z":"8e1afa9c.72c718","name":"","topic":"home/upstairs/office/motion","payload":"false","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":190,"y":480,"wires":[["74191c84.d19164"]]},{"id":"5e419626.d3e1c8","type":"mqtt in","z":"8e1afa9c.72c718","name":"","topic":"+/+/+/motion/occupied","qos":"0","datatype":"auto","broker":"2f3156fc.9fdc8a","x":160,"y":220,"wires":[["564234a4.303d3c"]]},{"id":"59c09eeb.8336","type":"mqtt in","z":"8e1afa9c.72c718","name":"","topic":"+/+/+/motion/presence","qos":"0","datatype":"auto","broker":"2f3156fc.9fdc8a","x":160,"y":160,"wires":[["564234a4.303d3c"]]},{"id":"564234a4.303d3c","type":"function","z":"8e1afa9c.72c718","name":"","func":"var presence = msg.payload\nvar topic = msg.topic\n\nvar topicchange = {\n    'home/upstairs/office/motion/presence': 'light.office_light',\n    'home/upstairs/hall/motion/presence': 'light.upper_hallway_light',\n    'home/downstairs/hall/presence': 'light.lower_hallway_light',\n};\n\n\nfor(var newtopic in topicchange) {\n    if(newtopic != msg.topic) continue;\n    var newMsg = {};\n        var occupied = context.get(topicchange[newtopic])\n        newMsg.topic = topic\n        newMsg.payload = {\n            entity_id : topicchange[newtopic]\n        }\n        newMsg.occupied = occupied\n        newMsg.presence = presence;\n    return [newMsg];\n}\n\n\nif (msg.topic.includes(\"upstairs/hall/motion/occupied\")) {\n    if (msg.payload == \"true\") {\n        context.set('light.upper_hallway_light', msg.occupied = \"true\")\n    }\n    if (msg.payload == \"false\") {\n        context.set('light.upper_hallway_light', msg.occupied = \"false\")\n    }\n}\nif (msg.topic.includes(\"upstairs/office/motion/occupied\")) {\n    if (msg.payload == \"true\") {\n        context.set('light.office_light', msg.occupied = \"true\")\n    }\n    if (msg.payload == \"false\") {\n        context.set('light.office_light', msg.occupied = \"false\")\n    }\n}","outputs":1,"noerr":0,"x":530,"y":220,"wires":[["4e6e4884.8b5be8"]]},{"id":"4e6e4884.8b5be8","type":"debug","z":"8e1afa9c.72c718","name":"","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"true","targetType":"full","x":690,"y":160,"wires":[]},{"id":"6e856aed.e3b024","type":"function","z":"8e1afa9c.72c718","name":"Room Presence/Occupation","func":"var msg1 = {\n    topic : msg.topic+\"/presence\",\n    payload : true\n}\nvar msg2 = {\n    topic : msg.topic+\"/presence\",\n    payload : false\n}\n\nvar resetentrancehall = {\n    topic : \"home/downstairs/hall/motion\",\n    payload : \"reset\"\n}\n\nvar resetdiningroom = {\n    topic : \"home/downstairs/diningroom/motion\",\n    payload : \"reset\"\n}\n\nvar resetkitchen = {\n    topic : \"home/downstairs/kitchen/motion\",\n    payload : \"reset\"\n}\n\nvar resetlivingroom = {\n    topic : \"home/downstairs/livingroom/motion\",\n    payload : \"reset\"\n}\n\nvar resetupstairshallway = {\n    topic : \"home/upstairs/hall/motion\",\n    payload : \"reset\"\n}\n\nvar resetdressingroom = {\n    topic : \"home/upstairs/dressingroom/motion\",\n    payload : \"reset\"\n}\n\nvar resetbedroom = {\n    topic : \"home/upstairs/bedroom/motion\",\n    payload : \"reset\"\n}\n\nvar resetoffice = {\n    topic : \"home/upstairs/office/motion\",\n    payload : \"reset\"\n}\n\nvar resettoilet = {\n    topic : \"home/upstairs/toilet/motion\",\n    payload : \"reset\"\n}\n\n// Entrance Hallway\n\nvar entrancehall = context.get('entrancehall') ;\n    if (typeof entrancehall == \"undefined\")\n    entrancehall = 0;\n\nif (msg.topic.includes(\"downstairs/hall\")) {\n    if (msg.payload == \"true\") {\n        msg.topic = msg.topic\n        context.set('entrancehall',entrancehall+1)\n        msg.payload = +entrancehall+1;\n        node.status({\n            fill: \"green\",\n            shape: \"dot\",\n            text: msg.topic\n        });\n        return [[msg, msg1, resetdiningroom, resetkitchen, resetlivingroom]];\n    }\n    if (msg.payload == \"false\") {\n        msg.topic = msg.topic\n        msg.payload = entrancehall\n        node.status({\n            fill: \"red\",\n            shape: \"dot\",\n            text: msg.topic\n        });\n        return [[msg, msg2]];\n    }\n    if (msg.payload == \"reset\") {\n        context.set('entrancehall',0)\n        msg.payload = 0\n        return msg;\n    }\n    if (msg.payload == \"3\") {\n        msg.topic = msg.topic+\"/occupied\"\n        msg.payload = true\n        return msg;\n    }\n    if (msg.payload == \"0\") {\n        msg.topic = msg.topic+\"/occupied\"\n        msg.payload = false\n        return msg;\n    }\n}\n\n// Dining Room\n\nvar diningroom = context.get('diningroom') ;\n    if (typeof diningroom == \"undefined\")\n    diningroom = 0;\n\nif (msg.topic.includes(\"downstairs/diningroom\")) {\n    if (msg.payload == \"true\") {\n        msg.topic = msg.topic\n        context.set('diningroom',diningroom+1)\n        msg.payload = +diningroom+1;\n        node.status({\n            fill: \"green\",\n            shape: \"dot\",\n            text: msg.topic\n        });\n        return [[msg, msg1, resetentrancehall]];\n    }\n    if (msg.payload == \"false\") {\n        msg.topic = msg.topic\n        msg.payload = diningroom\n        node.status({\n            fill: \"red\",\n            shape: \"dot\",\n            text: msg.topic\n        });\n        return [[msg, msg2]];\n    }\n    if (msg.payload == \"reset\") {\n        context.set('diningroom',0)\n        msg.payload = 0\n        return msg;\n    }\n    if (msg.payload == \"3\") {\n        msg.topic = msg.topic+\"/occupied\"\n        msg.payload = true\n        return msg;\n    }\n    if (msg.payload == \"0\") {\n        msg.topic = msg.topic+\"/occupied\"\n        msg.payload = false\n        return msg;\n    }\n}\n\n// Kitchen\n\nvar kitchen = context.get('kitchen') ;\n    if (typeof kitchen == \"undefined\")\n    kitchen = 0;\n\nif (msg.topic.includes(\"downstairs/kitchen\")) {\n    if (msg.payload == \"true\") {\n        msg.topic = msg.topic\n        context.set('kitchen',kitchen+1)\n        msg.payload = +kitchen+1;\n        node.status({\n            fill: \"green\",\n            shape: \"dot\",\n            text: msg.topic\n        });\n        return [[msg, msg1, resetentrancehall]];\n    }\n    if (msg.payload == \"false\") {\n        msg.topic = msg.topic\n        msg.payload = kitchen\n        node.status({\n            fill: \"red\",\n            shape: \"dot\",\n            text: msg.topic\n        });\n        return [[msg, msg2]];\n    }\n    if (msg.payload == \"reset\") {\n        context.set('kitchen',0)\n        msg.payload = 0\n        return msg;\n    }\n    if (msg.payload == \"3\") {\n        msg.topic = msg.topic+\"/occupied\"\n        msg.payload = true\n        return msg;\n    }\n    if (msg.payload == \"0\") {\n        msg.topic = msg.topic+\"/occupied\"\n        msg.payload = false\n        return msg;\n    }\n}\n\n// Living Room\n\nvar livingroom = context.get('livingroom') ;\n    if (typeof livingroom == \"undefined\")\n    livingroom = 0;\n\nif (msg.topic.includes(\"downstairs/livingroom\")) {\n    if (msg.payload == \"true\") {\n        msg.topic = msg.topic\n        context.set('livingroom',livingroom+1)\n        msg.payload = +livingroom+1;\n        node.status({\n            fill: \"green\",\n            shape: \"dot\",\n            text: msg.topic\n        });\n        return [[msg, msg1, resetentrancehall]];\n    }\n    if (msg.payload == \"false\") {\n        msg.topic = msg.topic\n        msg.payload = livingroom\n        node.status({\n            fill: \"red\",\n            shape: \"dot\",\n            text: msg.topic\n        });\n        return [[msg, msg2]];\n    }\n    if (msg.payload == \"reset\") {\n        context.set('livingroom',0)\n        msg.payload = 0\n        return msg;\n    }\n    if (msg.payload == \"3\") {\n        msg.topic = msg.topic+\"/occupied\"\n        msg.payload = true\n        return msg;\n    }\n    if (msg.payload == \"0\") {\n        msg.topic = msg.topic+\"/occupied\"\n        msg.payload = false\n        return msg;\n    }\n}\n\n// Upstairs Hallway\n\nvar upstairshallway = context.get('upstairshallway') ;\n    if (typeof upstairshallway == \"undefined\")\n    upstairshallway = 0;\n\nif (msg.topic.includes(\"upstairs/hall\")) {\n    if (msg.payload == \"true\") {\n        msg.topic = msg.topic\n        context.set('upstairshallway',upstairshallway+1)\n        msg.payload = +upstairshallway+1;\n        node.status({\n            fill: \"green\",\n            shape: \"dot\",\n            text: msg.topic\n        });\n        return [[msg, msg1, resetentrancehall, resetdressingroom, resetbedroom, resetoffice, resettoilet]];\n    }\n    if (msg.payload == \"false\") {\n        msg.topic = msg.topic\n        msg.payload = upstairshallway\n        node.status({\n            fill: \"red\",\n            shape: \"dot\",\n            text: msg.topic\n        });\n        return [[msg, msg2]];\n    }\n    if (msg.payload == \"reset\") {\n        context.set('upstairshallway',0)\n        msg.payload = 0\n        return msg;\n    }\n    if (msg.payload == \"3\") {\n        msg.topic = msg.topic+\"/occupied\"\n        msg.payload = true\n        return msg;\n    }\n    if (msg.payload == \"0\") {\n        msg.topic = msg.topic+\"/occupied\"\n        msg.payload = false\n        return msg;\n    }\n}\n\n// Dressing Room\n\nvar dressingroom = context.get('dressingroom') ;\n    if (typeof dressingroom == \"undefined\")\n    dressingroom = 0;\n\nif (msg.topic.includes(\"upstairs/dressingroom\")) {\n    if (msg.payload == \"true\") {\n        msg.topic = msg.topic\n        context.set('dressingroom',dressingroom+1)\n        msg.payload = +dressingroom+1;\n        node.status({\n            fill: \"green\",\n            shape: \"dot\",\n            text: msg.topic\n        });\n        return [[msg, msg1, resetupstairshallway]];\n    }\n    if (msg.payload == \"false\") {\n        msg.topic = msg.topic\n        msg.payload = dressingroom\n        node.status({\n            fill: \"red\",\n            shape: \"dot\",\n            text: msg.topic\n        });\n        return [[msg, msg2]];\n    }\n    if (msg.payload == \"reset\") {\n        context.set('dressingroom',0)\n        msg.payload = 0\n        return msg;\n    }\n    if (msg.payload == \"3\") {\n        msg.topic = msg.topic+\"/occupied\"\n        msg.payload = true\n        return msg;\n    }\n    if (msg.payload == \"0\") {\n        msg.topic = msg.topic+\"/occupied\"\n        msg.payload = false\n        return msg;\n    }\n}\n\n// Bedroom\n\nvar bedroom = context.get('bedroom') ;\n    if (typeof bedroom == \"undefined\")\n    bedroom = 0;\n\nif (msg.topic.includes(\"upstairs/bedroom\")) {\n    if (msg.payload == \"true\") {\n        msg.topic = msg.topic\n        context.set('bedroom',bedroom+1)\n        msg.payload = +bedroom+1;\n        node.status({\n            fill: \"green\",\n            shape: \"dot\",\n            text: msg.topic\n        });\n        return [[msg, msg1, resetupstairshallway]];\n    }\n    if (msg.payload == \"false\") {\n        msg.topic = msg.topic\n        msg.payload = bedroom\n        node.status({\n            fill: \"red\",\n            shape: \"dot\",\n            text: msg.topic\n        });\n        return [[msg, msg2]];\n    }\n    if (msg.payload == \"reset\") {\n        context.set('bedroom',0)\n        msg.payload = 0\n        return msg;\n    }\n    if (msg.payload == \"3\") {\n        msg.topic = msg.topic+\"/occupied\"\n        msg.payload = true\n        return msg;\n    }\n    if (msg.payload == \"0\") {\n        msg.topic = msg.topic+\"/occupied\"\n        msg.payload = false\n        return msg;\n    }\n}\n\n// Office\n\nvar office = context.get('office') ;\n    if (typeof office == \"undefined\")\n    office = 0;\n\nif (msg.topic.includes(\"upstairs/office\")) {\n    if (msg.payload == \"true\") {\n        msg.topic = msg.topic\n        context.set('office',office+1)\n        msg.payload = +office+1;\n        node.status({\n            fill: \"green\",\n            shape: \"dot\",\n            text: msg.topic\n        });\n        return [[msg, msg1, resetupstairshallway]];\n    }\n    if (msg.payload == \"false\") {\n        msg.topic = msg.topic\n        msg.payload = office\n        node.status({\n            fill: \"red\",\n            shape: \"dot\",\n            text: msg.topic\n        });\n        return [[msg, msg2]];\n    }\n    if (msg.payload == \"reset\") {\n        context.set('office',0)\n        msg.payload = 0\n        return msg;\n    }\n    if (msg.payload == \"3\") {\n        msg.topic = msg.topic+\"/occupied\"\n        msg.payload = true\n        return msg;\n    }\n    if (msg.payload == \"0\") {\n        msg.topic = msg.topic+\"/occupied\"\n        msg.payload = false\n        return msg;\n    }\n}\n\n// Toilet\n\nvar toilet = context.get('toilet') ;\n    if (typeof toilet == \"undefined\")\n    toilet = 0;\n\nif (msg.topic.includes(\"upstairs/toilet\")) {\n    if (msg.payload == \"true\") {\n        msg.topic = msg.topic\n        context.set('toilet',toilet+1)\n        msg.payload = +toilet+1;\n        node.status({\n            fill: \"green\",\n            shape: \"dot\",\n            text: msg.topic\n        });\n        return [[msg, msg1, resetupstairshallway]];\n    }\n    if (msg.payload == \"false\") {\n        msg.topic = msg.topic\n        msg.payload = toilet\n        node.status({\n            fill: \"red\",\n            shape: \"dot\",\n            text: msg.topic\n        });\n        return [[msg, msg2]];\n    }\n    if (msg.payload == \"reset\") {\n        context.set('toilet',0)\n        msg.payload = 0\n        return msg;\n    }\n    if (msg.payload == \"3\") {\n        msg.topic = msg.topic+\"/occupied\"\n        msg.payload = true\n        return msg;\n    }\n    if (msg.payload == \"0\") {\n        msg.topic = msg.topic+\"/occupied\"\n        msg.payload = false\n        return msg;\n    }\n}","outputs":1,"noerr":0,"x":360,"y":100,"wires":[["7366e0a7.a83e6"]]},{"id":"7366e0a7.a83e6","type":"mqtt out","z":"8e1afa9c.72c718","name":"","topic":"","qos":"0","retain":"true","broker":"2f3156fc.9fdc8a","x":570,"y":100,"wires":[]},{"id":"99f77908.9003d8","type":"mqtt in","z":"8e1afa9c.72c718","name":"","topic":"+/+/+/motion","qos":"0","datatype":"auto","broker":"2f3156fc.9fdc8a","x":130,"y":100,"wires":[["6e856aed.e3b024"]]},{"id":"dcbb3401.f29598","type":"comment","z":"8e1afa9c.72c718","name":"Manually inputted context.set in the above function","info":"","x":530,"y":260,"wires":[]},{"id":"2f3156fc.9fdc8a","type":"mqtt-broker","z":"","name":"","broker":"192.168.1.243","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthRetain":"false","birthPayload":"","closeTopic":"","closePayload":"","willTopic":"","willQos":"0","willPayload":""}]

Here's basically what I'm working with at the moment. So I'm able to take the context data depending on the topic, but not assign it, so I've put them in manually. There's probably a lot of mistakes in this, but it does what I wanted it to do.

Basically, if a room detects presence 3 times, it shows up at the end that it's occupied, so as not to try and turn out any lights. Simple stuff really, but I'm just making it overly complicated by not using other nodes.

I'll take a look at your code and see if there's anything I can take from it, as I just want to understand how it works, more than actually getting it to work. I can see how it works, thanks to all the great tool-tips, it's just figuring out how they can be applied elsewhere. It's all well and good copying and pasting, but that's not going to help me in the long term.

just keep in mind that should you have set nodered to save context data to the file system (https://nodered.org/docs/user-guide/context#saving-context-data-to-the-file-system) you will get circular errors when writing the handle you get from a setTimeout() to a flow or context variable as nodered is trying to serialise the data as far as I understand and this will not work for functions. There is a way around this using a "deprecated" way to set context.
You will have to use
context.timerhandlevar = timerhandle; instead of context.set("timerhandlevar", timerhandle);
and vice versa
timerhandle = context.timerhandlevar; instead of timerhandle = context.get("timerhandlevar")
to get the handle for clearTimeout()
Those two ways are not interchangeable.
Just something to keep in mind as it took me an afternoon to track this down when i ran into said errors.

Johannes

1 Like

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