-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add the ability to add child nodes conditionally in html!
#1609
Conversation
Forked at: 66d506e Parent branch: origin/master
I did it again, I AM SORRY!
I think it is great overall but let me know what you think before I tidy it up. It's okay to disagree and I won't be mad even if we would discard this PR. I think it is important to have good points on the table and debate. My points:
|
I like the idea very much, thank you for this implementation :) Looks good to me, but I haven't touched the vdom generator myself, so I'll leave it to the people familiar with that code to decide. |
I think I could also allow literals to be written directly in the macro like this: html! {
<label>"Hello"</label>
} (Notice the absence of |
Sorry it took so long to get to this. If this had been an issue I would've picked up the discussion much earlier but since you still had another PR open I wanted to get that one done first.
See #757. Personally, I wouldn't mind allowing string literals directly but if you want to push that, please do so over there. Now let's get on to the PR. I absolutely agree with your points. Conditionals and loops are an essential feature for ergonomic code. I'm glad that you took the initiative to start the discussion on this (even though you didn't bother opening an issue again :P). The reason we support this weird Now, I like the syntax you suggested but I want to make it more flexible. If we're adding this dedicated syntax, it should be usable without having to use html! {
<div>
if let Some(key) = &props.key {
<span>{ "KEY: " }</span>
<p>{ key }</p>
}
</div>
} Of course it should still support Rust code: html! {
<div>
if self.request.has_finished() {
let resp = self.request.read_response();
let status = resp.status();
html! { <span>{ status }</span> }
}
</div>
} Luckily for us, this is fairly easy to accomplish because the What's great about this is that it also removes the need for html! {
<OnlyAcceptsUser>
// works without the need for html_nested! because the type of the component is preserved
for user in &props.users {
<User key=user.id user=user />
}
</OnlyAcceptsUser>
} I also want to make sure that we support all these expressions:
The only one you didn't already add is the switch expression but I think that's the most exciting one! TL;DR I think we're 90% there with the concept, I just want to make sure we push it to its full potential. |
No problem.
Wait... I think I understand now. We see PR and issues differently. For you an issue is not a PR (very much like GitLab) and you like to discuss the specs on an issue (not a PR). While for me, PR and issue are actually the same, I just like to experiment a bit and give a concrete example to a long explanation of what I have in mind (example here where my idea turns out differently when I've put it in practice). But ok. Next time I will create an issue first. Sorry for that 🙏
Sure. I haven't started the code really. This is just a draft of what it could be and I didn't do the literals. I will make another PR for the literals and link it to that specific issue.
At the moment I'm using the "if-expression" parser documented here which is very handy. To achieve what you ask, I will need to split this out by parsing the token "if" separately, then the expression, then a block, then else, then a block again. It won't be as trivial as it is right now unless I'm missing something. In other words: I think it is simpler, it has less code and less maintenance.
Following the same reasoning I must say I'm not a big fan of the syntax you are proposing here because it makes the But again I don't have a strong opinion about this. Just letting you know I personally find it not intuitive. Maybe other people had a different experience when they used yew the first time. I think in React this syntax makes more sense because you don't prefix the JSX with a macro. JSX just "appears" there and we're kinda use to it. In rust we do expect macros to start with "some_name!". Macros can have blocks of code ( html! {
<div class=any_expression_i_can_think_of_which_evaluates_to_string>
{
// any valid Rust code
let x = 42;
any_normal_code_I_can_think_of();
// must ends with html!() or a VNode (but not a literal or a String)
}
</div>
} And I got really confused by this: html! {
<div>
{"Arbitrary literal"}
// I can't end a block by a literal but
// if I write a literal alone in a block it's ok
</div>
Surely you mean "match" and not "switch"? I agree it would be nice to have them all. Note that I believe the current implementation already supports the
It doesn't make sense to me either. I can't find a use case. But I do find a use case for the match/switch (for the router for example).
I'm not completely there yet. But almost. After #1626 I've been thinking a lot about these blocks (as I explained above already) and I did realize that this: html! {
<div>
{"Some literal"}
</div>
} Could be coded as a normal case of I also see a lot of value about adding a html! {
<div class="greetings">
{format!("Hello {}!", name)}
</div>
} (Maybe something like Let me know your opinion and in any case I'm totally fine implementing what you asked. I just feel I still have this experience of "first time using yew" which can be valuable to evaluate what feels or feels not rust-intuitive. But maybe other people will have a different idea on this concern about blocks in |
But it's also much less useful. Currently this is just a way to avoid writing
Yes, of course, sorry! I had the displeasure of working entirely with C last week.
I can see where you're coming from but the Instead of thinking about it like we're somehow allowing both, think about it like we're only allowing an html tree. html! {
if test {
{ rust_expression() }
}
} but now we just remove the requirement for the double braces So here's a quick rundown of the benefits of allowing an html tree inside of the block:
compared to the downsides:
If you can think of another way to achieve the same flexibility, I'm all ears. The only thing I care about is that it doesn't require a nested
Just to get you on the same page here. We're very likely going to remove the transformer logic entirely because it's a confusing mess. I'm not perfectly happy with how I would love to discuss this more if you want, feel free to open a new issue to discuss this.
Definitely appreciate that. Btw, in my experience other users are much more likely to chime in on issues rather than PRs :P |
A valid point 🤔 I also have this issue on yewprint. I was thinking about writing a rustfmt expressely for formatting the yew's
tbh I do see this as an anomaly. Those brackets are for delimiting the macro. They can even be
I've never used it either. I think I didn't understand it. So I agree it's an upgrade to remove it.
Rust does use
I guess I'm not normal.... |
This reverts commit 75b1a85.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this change especially after playing around with it :D
I agree with the discussions that it does make {for ...}
syntax feel awkward (but that's for another issue/PR).
I also want to make sure that we support all these expressions:
- if (also support else and else if)
- for
- switch - very useful for component state machines (ex. fetch request state: loading, ok, error)
Did you mean that before this can be merged all these have to be supported? or just that in the future they should be?
I think this PR will cover the if/else/else if/ if let/ part quite well, I would prefer another issue/PR for match (or switch for the C using Ferris traitors :P)
error: expected block after this condition | ||
--> $DIR/html-if-fail.rs:4:16 | ||
| | ||
4 | html! { if {} }; | ||
| ^^ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be expecting the condition here.
The {}
is being parsed because it is of type syn::Expr
and then you run out of tokens which trips your first input.is_empty() check.
I think most users would realise what the error was about, but I still don't think it's correct.
57a030b
to
a265d4d
Compare
@hamza1311 Could you add a short paragraph about this change somewhere under https://yew.rs/next/concepts/html ? |
Co-authored-by: mc1098 <m.cripps1@uni.brighton.ac.uk>
Visit the preview URL for this PR (updated for commit f0e6091): https://yew-rs--pr1609-html-if-macro-rrd1p0yv.web.app (expires Mon, 29 Nov 2021 16:01:00 GMT) 🔥 via Firebase Hosting GitHub Action 🌎 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
#1609 (comment) If you are curious Rust will spit out: error: missing condition for `if` expression |
Description
Add the ability to add child nodes conditionally in the
html!
macro.Alternative (not in the current commit):
When I first started to use yew I tried to do something like this:
Then I switched to something like this:
Question: why is
for
implemented inside the{ }
? (i.e.<div>{ for first.map(display) }</div>
Wait I think I know why... It would parse the closing tag as part of the expression, right?
But this would have been possible right?
<div>for { first.map(display) }</div>
I'm asking that question because the inconsistency I'm introducing in this PR between the
for
syntax and theif
syntax bothers me. I can revert to the alternative implementation without problem (I believe).Checklist
cargo make pr-flow