-
Let me say upfront that I'm new to Leptos, and I'm mainly a backend developer, so I'm definitely a web development n00b. What I'm trying to do is, when a button is pressed, have a modal dialog pop up which allows the user to add an object type with attributes. The dialog has input for the name of the type, and one or more attributes for the type. There's an initial attribute, but the user can click a button to add another attribute. To do this, I'm using a signal with an initial value of 1 for the number of attribute rows, and the button increments the signal, and (I'd hoped), re-renders the dialog with the correct number of attribute rows. However, what happens is, when the "Add row" button is clicked, the entire thing re-renders and the dialog disappears. Here's the relevant code: #[component]
pub fn App() -> impl IntoView {
// Provides context that manages stylesheets, titles, meta tags, etc.
provide_meta_context();
view! {
// injects a stylesheet into the document <head>
// id=leptos means cargo-leptos will hot-reload this stylesheet
<Stylesheet id="leptos" href="/pkg/knowledge-base-app.css"/>
// sets the document title
<Title text="Knowledge Base"/>
// content for this welcome page
<Router fallback=|| {
let mut outside_errors = Errors::default();
outside_errors.insert_with_default_key(AppError::NotFound);
view! {
<ErrorTemplate outside_errors/>
}
.into_view()
}>
<main>
<Routes>
<Route path="" view=HomePage/>
</Routes>
</main>
</Router>
}
}
/// Renders the home page of your application.
#[component]
fn HomePage() -> impl IntoView {
let dialog_ref: NodeRef<html::Dialog> = create_node_ref();
let (count, set_count) = create_signal(1);
view! {
<h1>"Library"</h1>
<ObjectTypeDialog dialog_ref=dialog_ref count=count set_count=set_count/>
<button
on:click=move |_| { dialog_ref.get().unwrap().show_modal(); }
>
<h1>Add</h1>
</button>
}
}
#[component]
fn ObjectTypeDialog(
dialog_ref: NodeRef<html::Dialog>,
count: ReadSignal<i32>,
set_count: WriteSignal<i32>,
) -> impl IntoView {
let datatypes = DataType::iter()
.map(|d| format!("{:?}", d))
.collect::<Vec<String>>();
view! {
<dialog
node_ref = dialog_ref
class = "modal">
<div>
<form>
<input
name = "name"
r#type = "text"
placeholder = "Name"/>
<div>
{
let mut rows = vec![];
for index in 0..count.get() {
let types = datatypes.clone();
rows.push(view! { <AttributeRow datatypes=types index=index/> });
}
rows
}
</div>
<div>
<button
on:click=move |_| { set_count.update(|count: &mut i32| *count += 1); }>
Add Row
</button>
</div>
<div>
<button
on:click=move |_| { dialog_ref.get().unwrap().close(); }>
Submit
</button>
</div>
</form>
</div>
</dialog>
}
}
#[component]
fn AttributeRow(datatypes: Vec<String>, index: i32) -> impl IntoView {
view! {
<div>
<input
name = format!("attribute-name{}", index)
r#type = "text"
placeholder = "Attribute Name"/>
<select
name = format!("datatype{}", index)>
<option
disabled = true
selected = true>
"Attribute DataType"
</option>
{datatypes.into_iter()
.map(|datatype| view! { <option> { datatype } </option> })
.collect::<Vec<_>>()}
</select>
</div>
}
} Clearly, I'm missing something here. I've looked through all the Leptos examples, but there's no example with a modal dialog that I can find, nor is there mention of using modal dialogs in the book, so any help would be greatly appreciated! Thanks, |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 2 replies
-
There are two separate issues here:
{
let mut rows = vec![];
for index in 0..count.get() {
let types = datatypes.clone();
rows.push(view! { <AttributeRow datatypes=types index=index/> });
}
rows
} I'm not sure which version you're using but there should be a warning in the browser console that actually points to
|
Beta Was this translation helpful? Give feedback.
-
Thanks for the quick response!!!
You're right. I didn't look at the console. 🤦 I made the changes you suggested. My loop now looks like this: <div>
{
move || {
let mut rows = vec![];
for index in 0..count.get() {
let types = datatypes.clone();
rows.push(view! { <AttributeRow datatypes=types index=index/> });
}
rows
}
}
</div> However, when I click on the "Add row" button, I now get this error in the console: Uncaught Error: called `Result::unwrap_throw()` on an `Err` value (/home/jack/.cargo/registry/src/index.crates.io-6f17d22bba15001f/leptos_dom-0.6.15/src/macro_helpers/into_attribute.rs:372:56): JsValue(InvalidCharacterError: String contains an invalid character
__wbg_get_imports/imports.wbg.__wbg_setAttribute_d5540a19be09f8dc/<@http://127.0.0.1:3000/pkg/knowledge-base-app.js:651:17
handleError@http://127.0.0.1:3000/pkg/knowledge-base-app.js:246:38
__wbg_get_imports/imports.wbg.__wbg_setAttribute_d5540a19be09f8dc@http://127.0.0.1:3000/pkg/knowledge-base-app.js:648:71
knowledge_base_app.wasm.web_sys::features::gen_Element::Element::set_attribute::had3379adcc8e5cef@http://127.0.0.1:3000/pkg/knowledge-base-app.wasm:wasm-function[1320]:0x238939
knowledge_base_app.wasm.leptos_dom::macro_helpers::into_attribute::attribute_expression::haea92a5a9afebcef@http://127.0.0.1:3000/pkg/knowledge-base-app.wasm:wasm-function[382]:0x150aea
knowledge_base_app.wasm.leptos_dom::macro_helpers::into_attribute::attribute_help…
__wbindgen_throw http://127.0.0.1:3000/pkg/knowledge-base-app.js:1176 The only place where it looks like I'm unwrapping something that might be a |
Beta Was this translation helpful? Give feedback.
There are two separate issues here:
I'm not sure which version you're using but there should be a warning in the browser console that actually points to
0..count.get()
here.{move || { let mut rows /* ... */
works, and see the Iteration chapter.<button>
inside a<form>
has a default behavior. In this case, clicking a button inside a form inside a dialog seems to have the default behavior of closing the dialog. You can prevent this by …