Dynamically change dashboard menu names without change of UI tab name

Anybody knows, if it is possible to dynamically change some menu item names in node red dashboard, independent of the UI tab name? In fact giving them an alias.

I don't have an answer, but out of curiosity, what is the use-case?

Keep a standard name for UI tab for showing and hiding, but UI-tab can be used for different devices thus always the same name. But menu should be friendly name that can change according to device used.

If possible that would be nice, but I have a plan B, but this is less friendly :slight_smile:

1 Like

Sounds like a good use-case, although it could also be confusing when tab names in the UI change all the time... Unfortunately, I can't help you with the std dashboard.

In FlexDash you can change the "title" of a tab as it shows in the tab bar as well as the icon (but there isn't a drop-down menu the way the std dashboard has it)...

No that isn’t possible with node-red-dashboard

Not quite ...
With ui_template node you can reach to the menu item label like this

<script>
    (function(scope) {
    scope.$watch('msg', function(msg) {
      if (msg) {
        // defined menu item name is aria-label of the menu button
        // select that button's parent and find a paragraph in it
        // set text of that paragraph to the msg.payload
        let defaultLabel = 'Two'
        $( "button[aria-label="+defaultLabel+"]").parent().find('p').text(msg.payload)
      }
    });
})(scope);
</script>
1 Like

@hotNipi I don't understand this part. I am no expert in this.
Can you explain a bit further, please?

How do I compose the msg.payload? Maybe, msg.payload = "New name" ?

let defaultLabel = 'Two'   // Is this the name of UI tab ??

Ok, I stay corrected. It is working well!!

The UI template should be part of the UI tab. That wasn't the case with me.
Thanks very much. That is exactly what I wanted!

The name next to the hamburger is still the UI tab name, but that is not really a problem.

let defaultLabel = 'Two' // Is this the name of UI tab?

Yes.

How to compose msg?

For this example msg.payload should be new name you wanted to show.

This example shows basics how to change the menu item label. How it can be used depends on your wishes and dashboard buildup and many more things. To advise it takes to know more about those. But if you can make this example working you probably find most of it by yourself.

@hotNipi It almost works perfectly, but when other UI tab is active and you refresh the screen, then the UI tab name is there again in the menu. Can that be solved some how?

For sure. Are you targeting one menu item only or several (may be all)?

@hotNipi No, just 4 out of 10 UI tabs. But if easier for all renaming, that is also an option

As dashboard can't remember "on fly" changes you'll need to send such changes any time the dashboard initializes (reload) (and mostly also when tab changes)
As the ui_template lives only at one specific tab - the code inside it can't do anything if that tab is not currently alive.
So you'll need to have duplicates of that functionality for each tab so it can work no matter the current tab is.

On top of that, you'll need to have some definition of the menu stored at server side. (global context maybe)
Let's say an array of menu items where every item is an object with default name and current name

menu = [
{defaultLabel:"Home",currentLabel:"Home"},
{defaultLabel:"Away",currentLabel:"Avay"}
....
]

As the menu is defined as an array, the code inside the ui_template must be changed to accept that array and deal with it a bit more abstract manner.

<script>
    (function(scope) {
    scope.$watch('msg', function(msg) {
      if (msg) {

      // msg.payload expected to be an array of objects something like this

      /*
        [{defaultLabel:"Home",currentLabel:"Lovely"},
        {defaultLabel:"Away",currentLabel:"Suddenly"},
        {defaultLabel:"Work",currentLabel:"Mandatory"}]      
      */
        
        if(!Array.isArray(msg.payload)){
          return
        }
        msg.payload.forEach(menuItem => {

          //menuItem ->  {defaultLabel:"Home",currentLabel:"Something"}

          // for each object (menuItem) in array lets find proper menu button
          // defined menu item name is also aria-label of the menu button
          // select that button's parent and find a paragraph in it
          // set text of that paragraph to the menuItem.currentLabel
          $("button[aria-label="+menuItem.defaultLabel+"]").parent().find('p').text(menuItem.currentLabel)
        })
      }
    });
})(scope);
</script>

When you need to change some name, you just get the menu object from context, find correct item in it, change the currentLabel value and store the menu object in context.
After that, the changed menu also needed to be sent to all those ui_templates (because of you don't know (and you really shouldn't care) which one is currently active)

Also the current menu state needs to be sent when dashboard initializes. For that there is ui_control node. No mater the payload, using it just as an event based trigger, again send current menu state to dashboard.

That's all in theory.
I can make full example based on this story but I do prefer that you first at least try to manage it working by yourself.

@hotNipi Thanks for your extensive explanation. I learned a lot this way.
This is indeed the solution in my case.

I have implemented it as you suggested, and I think now it is 100% full-proof.

Thanks again for your support !!!!

1 Like

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