Guys, how do I add/remove menu choices on the navigation menu of the Dashboard form at runtime via code? I’m using the Dashboard form as my “main” form, with all other forms loading within it. As I load each new form, I need to add/remove menu choices in the navigation bar that are specific to the freshly loaded form.
Guys, something just occurred to me. Instead of adding/removing menu choices at runtime, perhaps what I need to do is define ALL my menu choices on the navigation menu, and then hide/show them at runtime.
Hi Peter,
It’s probably simplest to have all the possible menu items on your form, and then set the visible
property to True
or False
to show and hide them.
That said, here’s a more advanced guide to controlling HTML-templated forms like the Dashboard:
If you add a component directly to a templated form like the Dashboard (rather than adding to a panel on the page), you’ll see the add_component()
method has an optional keyword parameter called slot
. This lets you name where in the page your component will land. Eg:
google_link = Link(url="https://google.com", text="Visit Google")
self.add_component(google_link, slot='sidebar')
In the Dashboard layout, specifying the sidebar
slot will put the component in the side navigation. Specifying nav-right
will place it in the top-right navigation bar. Here’s a more involved example:
logout_link = Link(text="Log out", icon="fa:sign-out")
def do_logout(**e):
anvil.users.logout()
open_form('LoggedOut')
logout_link.set_event_handler('click', do_logout)
self.add_component(logout_link, slot='nav-right')
You can explore the slots yourself by dropping components in various points on the page, and then looking in their “Container properties” for their slot
value.
For more information about how Anvil’s HTML templating slots work, and how to create your own, you can check our reference documentation.
Hope that helps!
(Looks like you decided to go with showing/hiding options. I’d agree that sounds like the best choice for you, but hopefully this guide could prove useful to someone else )
Understood Meredydd, thanks!
Ok, this is trivial, but I just noticed that when I hide (.visible = False) a navigation menu choice, the horizontal separator line beneath the now hidden choice is still present, and “joins” with the menu choice above, creating a separator line that’s thicker than the other separator lines.
So it does! I guess you’ll have to remove_from_parent()
and add_component()
those menu options dynamically after all. Make sure to use slot='sidebar'
.
Meredydd, I can’t figure out how to use remove_from_parent() to remove a link, one that’s either defined statically on the form or one that I add dynamically at runtime. It would seem I need to dynamically get a reference to the link and then remove it. EDIT: Never mind the static link, I can delete it. But not a link added dynamically.
remove_from_parent()
is working for me on even dynamically-added links. Here’s a sample app:
https://anvil.works/ide#clone:3PYDKJA7L2W2TKNH=EDWRTUVPB2VH7IY7ZP73S4T3
Ah, I see what I did wrong. When I created the link, I didn’t precede my link variable with “self.”. Works now! Thanks!
Great!
Here’s a bit of background information if you’re interested:
Assigning that component to self.xxx
is about making sure you still have a way of getting hold of that component later, using Python’s object-orientation features. Consider this example:
def button_1_click(self, **event_args):
# This function runs when the button gets clicked
my_link = Link(text="Hello")
self.add_component(my_link, slot="sidebar")
This works - it will add a new link to the sidebar when you click a button. But the variable my_link
is a local variable - it goes away when the function finishes running. This is problematic if you want to do something with that link later (eg remove it).
Python gives us a way to get around that problem. Every method (that is, a function within a class), takes a parameter called self
. self
refers to the object this method is being called on (in this case, the Form itself). When you call another method on this object, that method will get the same self
object.
This means that we can “remember something for later” by stick it onto self
:
self.my_link = Link(text="hello")
Now, we can get at that link object anywhere we have that form object. (eg, any other button-click handler on the same form can just refer to self.my_link
.)
There’s a bunch more to learn about Python object-orientation. This interactive tutorial might help you explore more about Python classes and the meaning of self
.
Hope that helps!