Kitware / trame-router

trame-router brings Vue Router capabilities into trame widgets and ui
MIT License
1 stars 0 forks source link

Surprising results using routers #4

Open gabrielfougeron opened 1 month ago

gabrielfougeron commented 1 month ago

Hi,

I'm a trame beginner, and I cannot tell whether the results I'm getting are expected or if there is a bug. I've modified the example at https://github.com/Kitware/trame-router/blob/master/examples/vue2/basic.py to show what I mean:

from trame.app import get_server
from trame.ui.vuetify import SinglePageWithDrawerLayout
from trame.ui.router import RouterViewLayout
from trame.widgets import vuetify, router
import trame.widgets.html as html

server = get_server()
server.client_type = "vue2"
state, ctrl = server.state, server.controller

def create_table():
    row = vuetify.VRow(style="height: 100%")
    with row:
        with vuetify.VCol() as col:            
            row.col = col
    return row

# Home route
home = RouterViewLayout(server, "/")
with home:

    with vuetify.VCard():
        vuetify.VCardTitle("This is home")

    home.table = create_table()

# Foo route
with RouterViewLayout(server, "/foo") as foo:
    with vuetify.VCard():
        vuetify.VCardTitle("This is foo")
        with vuetify.VCardText():
            vuetify.VBtn("Take me back", click="$router.back()")

# Bar/id
with RouterViewLayout(server, "/bar/:id"):
    with vuetify.VCard():
        vuetify.VCardTitle("This is bar with ID '{{ $route.params.id }}'")

# Main page content
with SinglePageWithDrawerLayout(server) as layout:
    layout.title.set_text("Multi-Page demo")

    with layout.content:
        with vuetify.VContainer():
            router.RouterView()
            table = create_table()

    # add router buttons to the drawer
    with layout.drawer:
        with vuetify.VList(shaped=True, v_model=("selectedRoute", 0)):
            vuetify.VSubheader("Routes")

            with vuetify.VListItem(to="/"):
                with vuetify.VListItemIcon():
                    vuetify.VIcon("mdi-home")
                with vuetify.VListItemContent():
                    vuetify.VListItemTitle("Home")

            with vuetify.VListItem(to="/foo"):
                with vuetify.VListItemIcon():
                    vuetify.VIcon("mdi-food")
                with vuetify.VListItemContent():
                    vuetify.VListItemTitle("Foo")

            with vuetify.VListGroup(value=("true",), sub_group=True):
                with vuetify.Template(v_slot_activator=True):
                    vuetify.VListItemTitle("Bars")
                with vuetify.VListItemContent():
                    with vuetify.VListItem(v_for="id in [1,2,3]", to=("'/bar/' + id",)):
                        with vuetify.VListItemIcon():
                            vuetify.VIcon("mdi-peanut-outline")
                        with vuetify.VListItemContent():
                            vuetify.VListItemTitle("Bar")
                            vuetify.VListItemSubtitle("ID '{{id}}'")

    with table.col:
        html.Div("This message shows on bottom")

    with home:
        html.Div("This message shows on top")

    with home.table.col:
        html.Div("This message does not show anywhere")

if __name__ == "__main__":
    server.start()

I added three html.Divs in the example (last lines). Only two of them show up in the UI, and I cannot make sense of why.

image

Could you please help me understand what is happening?

Cheers,

Gabriel Fougeron

gabrielfougeron commented 1 month ago

For some reason, it seems that manually adding a home.flush_content() before server.start() solves the problem.

I think this is a bug. Can you confirm ?

jourdain commented 1 month ago

Could you explain what is your intent in doing that?

def create_table():
    row = vuetify.VRow(style="height: 100%")
    with row:
        with vuetify.VCol() as col:            
            row.col = col
    return row

# Home route
home = RouterViewLayout(server, "/")
with home:

    with vuetify.VCard():
        vuetify.VCardTitle("This is home")

    home.table = create_table()

I don't understand what you try to do when you assign home.table, row.col as well as the hierarchy you aim to build?

Also at the exit of any with, that is when the flush_content is called. So if you properly define your hierarchy, you should be fine on the first go.

jourdain commented 1 month ago

Are you trying to do the following?

with RouterViewLayout(server, "/"):
   with vuetify.VCard():
      vuetify.VCardTitle("This is home")
   with vuetify.VRow(style="height: 100%"):
      vuetify.VCol()
gabrielfougeron commented 1 month ago

Thanks @jourdain for your response.

Also at the exit of any with, that is when the flush_content is called. So if you properly define your hierarchy, you should be fine on the first go.

Indeed, flush_content is called in the __exit__ method of AbstractLayout. It is AFAIK not called in the exit method of anything deriving from AbstractElement. I think my problem stemmed from not understanding the distinction between those two.

If the tutorial made a distinction between those two notions (key to what you call "properly define your hierarchy"), I probably would have had an easier time.

jourdain commented 1 month ago

You are correct, only the layout will flush itself at the exit of its with.

So to summarize:

The with notation of a widget ensure that every created widget within the context gets added as a child to the element in context. While for the layout, on top of the previously defined behavior, the flush_content method will be called on exit.

If you see a good spot to add the text above, feel free to add a PR or suggest a location for it.