I'm trying to create a Menu component similar to nested_list example. I successfully create them, so creating menus looks good and compiler guaranties, that <Menu> contains only <MenuItem> elements:
html!{
<Menu>
<MenuItem>{"item 1"}</MenuItem>
<MenuItem>{"item 2"}</MenuItem>
<MenuItem>{"item 3"}</MenuItem>
//<div /> -- not compiled which is good!
</Menu>
}
Now I want to compose that Menu component with TreeTable component and add menu that can manipulate visibility of columns. So I need to populate menu based on columns text.
html!{
<Menu>
{for self.columns.iter().map(|column| ???)}
</Menu>
}
That is not compiled, because {for ...} returns Html (aka VNode), and not the MenuItem component. So is there any way to create MenuItem by code like that?
You're looking for the html_nested! macro which works exactly like the html! macro but returns the actual component type instead of Html.
use yew::macros::html_nested;
html! {
<Menu>
{ for self.columns.iter().map(|column| html_nested! { <MenuItem>{ column }</MenuItem> }) }
</Menu>
}
Thanks for that macro! I wonder why it's not documented? When this work for single element, unfortunally, this not work for for loops. So this works
html! {
<Menu>
{ html_nested! { <MenuItem></MenuItem> }
</Menu>
}
but this not
html! {
<Menu>
{ for self.columns.iter().map(|column| html_nested! { <MenuItem>{ column }</MenuItem> }) }
</Menu>
}
and this
html! {
<Menu>
{html_nested!{ for self.columns.iter().map(|column| html_nested! { <MenuItem>{ column }</MenuItem> }) }}
</Menu>
}
I think this has come up before. I'll create an issue calling for it to be documented if there isn't already one.
We already have an issue! https://github.com/yewstack/yew/issues/1428
@Mingun ah, you're right, using for implicitly converts the items to Html too.
This should work:
let items: Vec<MenuItem> = self
.columns
.iter()
.map(|column| html_nested! { <MenuItem>{ column }</MenuItem> })
.collect();
html! {
<Menu>
{ items }
</Menu>
}
@siku2 , thank! With small change thats work. Type should be Vec<VChild<MenuItem>>:
let items: Vec<VChild<MenuItem>> = self
.columns
.iter()
.map(|column| html_nested! { <MenuItem>{ column }</MenuItem> })
.collect();
html! {
<Menu>
{ items }
</Menu>
}
oh right, forget to wrap it in VChild.
FYI, the fact that it wasn't working with { for ... } is a bug, I opened an issue for this here: #1527.
Ok, so I think that this issue can be closed, because there is already a task for documentation, and now also a bug. Thanks for you help!