-
Apologies if this is a silly question, but I'm still a newbie to Sycamore and Rust. I'm trying to use sycamore routers to pass down a url as a props into my navbar, e.g. I can achieve this using the builder API by doing a bunch of clones and moves of the string, but I have no idea how to achieve this using the Appreciate the hard work in building the library so far! Problematic code using the view!#[component]
fn NavBarEndMenuDsl<'navbar, G: Html>(cx: Scope<'navbar>, props: NavBarProps<'navbar>) -> View<G> {
let subapp = props.subapp;
let login_url = format!("/public/{}/trigger_login", &subapp);
let logout_url = format!("/api/{}/trigger_logout", &subapp);
view! {
cx,
div(class="navbar-end"){
(
if *props.is_logged_in.get() {
view! {cx,
div(class="navbar-item has-dropdown is-hoverable"){
a(class="navbar-link", href="#"){
"User:" (*props.username.get())
}
div(class="navbar-dropdown"){
// having trouble passing it in here into href ---------------
// |
// |
a(class="navbar-item", href=logout_url.clone(), rel="external"){
"Logout"
}
}
}
}
} else {
view! {cx,
a(class="button is-black", href="/public/trigger_login", rel="external"){"Login"}
}
})
}
}
}
#[derive(Prop, Clone)]
pub struct NavBarProps<'navbar> {
username: &'navbar Signal<String>,
is_logged_in: &'navbar ReadSignal<bool>,
subapp: String,
} Working code using the Builder API#[component]
fn NavBarEndMenu<'navbar, G: Html>(cx: Scope<'navbar>, props: NavBarProps<'navbar>) -> View<G> {
let subapp = props.subapp;
let login_url = format!("/public/{}/trigger_login", &subapp);
let logout_url = format!("/api/{}/trigger_logout", &subapp);
let root = div().class("navbar-end");
root.dyn_if(
|| *props.is_logged_in.get(),
move || {
let logout_url = logout_url.clone();
div()
.class("navbar-item has-dropdown is-hoverable")
.c(a()
.class("navbar-link")
.attr("href", "#")
.dyn_t(|| props.username.get().to_string()))
.c(div().class("navbar-dropdown").c(a()
.class("navbar-item")
.dyn_attr("href", move || Some(logout_url.clone()))
.attr("rel", "external")
.t("Logout")))
},
move || {
let login_url = login_url.clone();
a().class("button is-black")
.dyn_attr("href", move || Some(login_url.clone()))
.attr("rel", "external")
.t("Login")
},
)
.view(cx)
} |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments
-
This is because the |
Beta Was this translation helpful? Give feedback.
-
Thanks for the detailed explanation about the chaining of closures. Was not aware of |
Beta Was this translation helpful? Give feedback.
This is because the
(...)
in the view! macro implicitly creates amove ||
closure. and so does thehref=...
. This means that the value is moved into the first closure and then moved into the second closure which is not allowed because that would make the first one aFnOnce
. One way to solve this is to either clonelogout_url
right before theif
andelse
but inside the(...)
. Another way is to uselogout_url = create_ref(format!(...))
instead and uselogout_url.to_string()
instead.