Last active
February 6, 2025 12:32
-
-
Save finetjul/30e7daa1243d87ace139a2063e250cb9 to your computer and use it in GitHub Desktop.
Vue2 nested state example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from trame.app import get_server | |
from trame.widgets import vuetify, html, client | |
from trame.ui.vuetify import SinglePageWithDrawerLayout | |
# ----------------------------------------------------------------------------- | |
# Trame setup | |
# ----------------------------------------------------------------------------- | |
VAR_NAMES = set(["a123", "a456", "a789"]) | |
server = get_server(client_type="vue2") | |
state, ctrl = server.state, server.controller | |
count = 800 | |
state.update( | |
{ | |
"items": [{"id": "a123"}, {"id": "a456"}, {"id": "a789"}], | |
"a123": { | |
"range": (10, 90), | |
"range_min": 0, | |
"range_max": 100, | |
"opacity": 1, | |
}, | |
"a456": { | |
"range": (20, 80), | |
"range_min": 0, | |
"range_max": 100, | |
"opacity": 1, | |
}, | |
"a789": { | |
"range": (30, 70), | |
"range_min": 0, | |
"range_max": 100, | |
"opacity": 1, | |
}, | |
} | |
) | |
def add_entry(): | |
# !!! Vue2 does not support new vars with getter but vue3 should handle it | |
global count | |
count += 1 | |
key = f"a{count}" | |
state.items.append(dict(id=key)) | |
state[key] = { | |
"range": (0, 100), | |
"range_min": 0, | |
"range_max": 100, | |
"opacity": 0.5, | |
}, | |
state.dirty("items") | |
VAR_NAMES.add(key) | |
state.change(key)(on_change) | |
update_layout() | |
@state.change(*VAR_NAMES) | |
def on_change(**_): | |
for name in state.modified_keys & VAR_NAMES: | |
print(f"Data changed for {name}") | |
print(state[name]) | |
print("-" * 30) | |
if name == "a123": | |
state.a456["range"] = list(state.a123["range"]) | |
state.dirty("a456") | |
def update_layout(): | |
with SinglePageWithDrawerLayout(server) as layout: | |
with layout.toolbar: | |
vuetify.VSpacer() | |
vuetify.VBtn("Add", click=add_entry) | |
vuetify.VBtn("Fast: {{fast}}", click="fast = !fast") | |
with layout.drawer: | |
with client.Getter( | |
v_for="(item, i) in items", | |
key="item.id", | |
name=("`${item.id}`",), | |
key_name="local_name", | |
value_name="local_var", | |
update_nested_name="update_local", | |
): | |
with vuetify.VListItem(): # Must only be 1 child for a Getter | |
vuetify.VRangeSlider( | |
label=("`${local_name}`",), | |
value=("local_var.range",), | |
input="update_local('range', $event)", | |
min=("local_var.range_min",), | |
max=("local_var.range_max",), | |
) | |
vuetify.VSlider( | |
value=("local_var.opacity",), | |
input="update_local('opacity', $event)", | |
min=0, | |
max=1, | |
step=0.01, | |
) | |
with layout.content: | |
with vuetify.VRow(): | |
# With static HTML, the proper dependency get captured and state will print faster | |
with vuetify.VCol(v_if=("fast", True)): | |
html.Div("Static dependencies", classes="text-h6") | |
for name in VAR_NAMES: | |
html.Pre("%s = {{ %s }}" % (name, name)) | |
# With method call in template, the refresh is debounced unless proper dep above | |
with vuetify.VCol(): | |
html.Div("Use method call", classes="text-h6") | |
with html.Div( | |
"State: {{ item.id }}", v_for="item, idx in items", key="item.id" | |
): | |
html.Pre("{{ get(item.id) }}") | |
if __name__ == "__main__": | |
update_layout() | |
server.start() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment