If I'm understanding this, we ignore any and all messages untill we receive our own?
Yep. The only message which can happen before init message is replaymessage. I tested slightly, it worked for me.
Hey @Steve-Mcl,
I think we should give @hotNipi the Node-RED award for creativity this week Very simple workaround, so I got to love it ...
On the other hand, it is so pitty that we cannot handle this kind of stuff in the dashboard code (so all contributions could benefit from a standard solution). Did some debugging and I was almost close, but no sigar:
-
As soon as an input message arrives, that input message is being stored (with the node id as key) in
replayMessages
: -
Immediately afterwards the 'ui-replay-state' event is triggered, and the handler will get the message (for this node id from
replayMessages
) and send it to the browser:So the message really needs to be in
replayMessages
, otherwise it will never be send to the browser! -
But when I deploy my flow, I again arrive in the same event handler. So the same message will be send to the browser here, which is not what I want.
I don't see any way to avoid the ui-replay-state event being triggered, so I tried if I could remove the message from the replayMessages
variable. When we call addWidget
in our node, and I debug into that function I see that the replayMessages
is indeed available in the ui.js:
When I execute (inside the add
function) the following in my Chrome debugger console:
delete replayMessages[opt.node.id];
Then the event handler has no message to send to the browser (for the current node id), so no contextmenu appears, so problem solved.
@dceejay: is there any way we can access the replayMessages
variable from our node (just before we call addWidget
)? Here my Javascript knowledge suddenly ends ...
Or if we have no access to the replayMessages
, a new option replayAfterDeploy
could also be a solution:
Just an idea ...
I smell a PR to dashboard
Morning Steve (@Steve-Mcl),
a PR for the dashboard? I have no idea what you are talking about
Damn, you have published my hidden agenda on the www
But perhaps the dashboard master has other/better plans. Only time will tell ...
I think it will be correct if you do it in opposite manner.
Something like if(opt.avoidReplayOnDeploy)
then it will be backward compatible and does not affect any existing behavior.
Sorry guys, late to this party so probably missing something. This is the state of the input, not an event. So when a second client arrives if it can get put into the current state. If a client is already attached and in that state it can ignore it surely ?
Well for context menu type of widget (which should act mostly on user input) the state sharing hardly can do something useful. Or what?
@hotNipi: yes you are right that for our case a second client surely doesn't need to start with the contextmenu of another client. Had never tought about that until now... That makes it even more necessary for us to get this solved. So it is indeed a good remark from Dave! But then a flag named "avoidReplayOnDeploy" doesn't really makes sense anymore...
Don't forget - although I say a second client - this is still not multi-user. There is only one flow running with one overall state. People can do clever tricks using sessions etc to try and separate out different clients but the overall state is still the overall state.
That's the basis of my thinking. For single user, (no matter if equipped with two hands) the multiple context menus to operate at same time is definitely too much (excluding lady's multitasking skills. Full respect ). But anyway, I really can't see is there any possible destructive scenario?
Evening @hotNipi,
I'm experimenting with your workaround, but cannot get it working...
So we create a message a frontend, send it to backend, and then we will receive it again at the frontend. But I never receive it again in my message watch...
Indeed when you look at the handler (for messages coming back from the UI), you see that storeFrontEndInputAsState
needs to be true (to make sure that the message is stored in replayMessages
to overwrite the original message):
When I set this boolean to true
, then my own message again arrives in the frontend (so no contextmenu is displayed anymore immediately after a deploy ). But as you can see in the above handler (line 279) that own message will also be send on the output of our node. And that is not what we want
P.S. In my test the scope.unique
is undefined?
P.S. Think I'm misinterpreting your workaround. While I try to overwrite the original message in the replayMessages
array, it looks like your are ignore all messages until your arrives. But not sure how to get the same result as you
@BartButenaers, do you know the reason for dashboard to resend messages on deploy? Isn't there a flag to turn this feature off when registering the widget?
$scope.unique
I used as I tested the workaround with my ui_level
node and this is unique identifier what you get from $scope.unique = $scope.$eval('$id')
I think it is not needed in this case at all.
In line 279. If you don't want some message to be passed to next node, set
msg._fromInput = true. You can set it true for your init message and it should then be dropped. But as you can see the comment line - this is kind of hack or temporary solution (many of such last forever), used by native dashboard widget ui_dropdown.js and you'll never know if or when it will be changed or removed. Without any warnings. So this is something I'd not recommend to use as reliable solution. (of course it can be discussed with master)
Morning @Steve-Mcl,
At deploy the replayMessages array contains a message with our node id, so that is replayed. Cannot remove it from the array (since I think I have no access to that array?). And there is no flag that allows me to avoid my message getting stored in the array. So will need to be handled by the dashboard, but Dave responded above that you then impact other clients connecting (which means it becomes harder again to find a good solution to fit for other use cases)...
Hey @hotNipi,
Had considered that also last night (for about 3 seconds ). But like you say, the comments are pretty clear that this might change very probably in the (near) future. So I'm afraid I cannot get around it with a simple workaround: the server side stores the message in the replay array, and replays it. Wanted to avoid having to disturb our friend @dceejay, but I'm afraid I cannot workaround this...
Did you tested it also within that time or it is lucky guess it is working?. Cos I didn't test that all, just reading the code.
Will try that tonight. Thanks for the tip !!
@dceejay,
Very clever that you have thought about that!!!!!!!!!!
Indeed the last message is stored (in the replayMessages array) and send to any dashboard that needs initial state (e.g. refresh existing dashboard or open new dashboard). So for our Contextmenu-node that is very unwanted behaviour.
Did a quick test: when second dashboard is refreshed, it will get the last contextmenu of the previous dashboard. Here is a demo with two dashboards for interested readers:
Your suggestion is indeed very simple to implement, and it seems to work (both for refreshing a dasbhoard and in combination with a second dashboard). Thanks a lot for helping us with this!!!
Here it is, in case anybody ever needs it:
$scope.init = function (config) {
// Ignore all input messages that arrive within 1 second after creation of this widget.
// This way we can avoid the last old message being resend from server to the client...
$scope.acceptMessages = false;
setTimeout(function() {
$scope.acceptMessages = true;
} , 1000);
}
$scope.$watch('msg', function(msg) {
// Ignore undefined messages.
if (!msg) {
return;
}
if (!$scope.acceptMessages) {
return;
}
// Process the input message ...
Only the time interval of 1 second is a bit of a trial-and-error:
- If I use a larger interval, then I don't get a context menu when I immediately click on a shape.
- If I use a smaller interval, then the old messages might be replayed.
So in my case 1 second works fine. But I could image that this isn't the case in some other setups, e.g. due to a slow internet connection? And adding an extra input field to our config screen (to make the time adjustable by the user) might confuse users, since it is a rather technical issue ...