-
-
Notifications
You must be signed in to change notification settings - Fork 407
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
Nested Glimmer Syntax + attr/component-centric slots #203
Conversation
I like the idea of nested syntax in templating.
Instead of just reiterating what's already pointed out in the RFC and echoing it back, here's maybe some quick thoughts on ways around this:
{{#mdl-table header=(|data|
{{#mdl-table-heading}}Id{{/mdl-table-heading}}
{{#mdl-table-heading}}Name{{/mdl-table-heading}}
) content=rows as |row|}}
{{#mdl-table-col}}
{{row.id}}
{{/mdl-table-col}}
{{#mdl-table-col}}
{{row.name}}
{{/mdl-table-col}}
{{/mdl-table}} Compare this to the existing syntax which requires parent component support and child {{#mdl-table content=rows as |row|}}
{{#mdl-table-col label='Id'}}
{{row.id}}
{{/mdl-table-col}}
{{#mdl-table-col label='Name'}}
{{row.name}}
{{/mdl-table-col}}
{{/mdl-table}} |
I think there is some real cognitive dissonance in our UI programming model that you're getting at here: we want to treat components like any arbitrary data that can passed around in templates but also like markup that adds semantic structure to our templates. This proposal pushes us more towards the react model of treating all components and markup like data that can be passed around arbitrarily, whereas yield and named slots pretty much keeps us where we currently are just with slightly extended syntax and capability. Additionally, with this RFC we will basically nix nesting components the same way we nest html and will also have the freedom to intermingle data attributes and nested markup assigned to attributes, neither of which I'm crazy about. Personally, I'm not convinced that going to one extreme of our cognitive dissonance about components being markup vs. data just for consistencies sake of having OneTrue(TM) model is a great idea. Instead, maybe we can manage the dissonance with established, recognizable patterns like contextual components and the like? |
There is no "same way as html" to pass multiple chunks of markup to an element. There is only a moving target of a Web Component's RFC that many are not particularly enthusiastic/optimistic about. Slots require syntactical extension just as this RFC does. As for data/markup intermingling: we already have this with I do not share your optimism that the dissonance can be managed and tamed by recognizable patterns; Ember already has too many split-brained APIs where a problem can be solved 90% of the way by one pattern/feature and 91% of the way by another separate/feature with ever-so-slightly different semantics; having to explain why/when to use |
I guess I meant "in a similar way to html", meaning in the same spirit.
There is more precedent for slot syntax than just web components. The following essentially has the same block syntax/semantics (sans block params) as my proposal for slots: {{#if something}}
{{! stuff }}
{{else if somethingElse}}
{{! other stuff }}
{{else}}
{{! more stuff }}
{{/if}} This is something that everyone in Ember uses always.
I would say that's a different level of intermingling than this RFC.
I'm not sure I've ever encountered anyone asking when to use |
@sclaxton (we've probably discussed most of this in the Slack channel but good to share here) I 100% agree that your (and some others') slots proposals look way more familiar and Ember-y than what I'm proposing. I also agree that the fact that this proposal is such a shift from the evolutionary momentum of certain Ember patterns is one of the major drawbacks, and certainly shouldn't be taken lightly.
The debatable word here is "structural"; I think we'd do ourselves a disservice to limit our concept of "structural" to that which happens to be
So that we don't have to teach as many concepts and so that more things seamless fit together in Ember. Multiple concepts require translation layers between wherever you bridge between the two concepts. The RFC makes a strong case that building off of |
Would you say the place of partials could come into play here? Cause speaking just for me, and i know it's really just sugar in actuality, but if you where to just pull out these blocks and put them into a sperate partial file, i'm able to swallow the concept easier. Would you consider the partial/separate file approach able to live alongside the more inline approach? That way it might fulfil the desires of the "practicalists" while being the "spoon full of sugar" for the "purists"? |
@webark Partials I think are generally considered an anti-pattern, since the way they're essentially passed the entire template scope makes them very brittle and difficult to reuse in different contexts. Also, the |
@machty I bet someone skilled enough with AST transforming stuff could create an addon that doesn't even modify glimmer or anything and implement this proposal. The addon would need to:
For example, the generated components could be registered using a name like:
where Then we could start using this |
@machty i totally get that it's a perception thing. I understand that partials are considered an "anti-pattern" but it's currently the only way to do code reuse in a given template. And i thought partials weren't passed the whole scope in, but grabbed and executed in place. Cause for me, even though i understand the power of it, it looks like poor form to be passing html into an attribute. I get that's it's basically the same thing as passing a component using the helper, but it just looks kind of like old callback hell, that we all (and i can imagine for you specifically) shutter at a bit when we see. I'm just trying to think of ways that we can keep the power of this pattern, but have it look better (at least to me). |
@les2 I thought of something similar but got stuck on the following: how would you pass in the closed-over scope?
|
@webark Do you consider the following to be callback heck? {{x-foo as |a|}}
{{x-bar as |b|}}
{{x-woot as |c|}}
<p>Hello! {{a}} {{b}} {{c}}</p>
{{/x-woot}}
{{/x-bar}}
{{/x-foo}} Because that's valid (and community-validated/adopted) syntax today and solves many use cases for which only one/main/default template block needs to be passed, but it's still semantically the same degree of "callback-y-ness" and closed over scope as what this RFC proposes. |
Here's an experiment where my attr/component-centric semantics are combined with the slot syntax that @sclaxton came up with in his RFC. Instead of the recursively-nestable syntax that I proposed (e.g. This is a translation of the Recursive Nesting example from my RFC.
It's hard to tell if what I'm proposing is semantically scary or only syntactically scary, so maybe this experiment will help answer the question. (fwiw if we like this, we'd probably need to come up with a reasonable angle-bracket syntax equivalent) edit: major use case that this missesUsing bold headers because I keep forgetting this important use case: if we used this syntax then there'd be no way to use slot syntax to express an array of blocks, which is a strong use case for certain components that let you, say, define all the columns in a table component. Thanks to @mmun for pointing this out. |
How do your syntax changes fit into vanilla Handlebars that doesn't have a concept of components or yielding? |
I don't know. |
you could pass those in as attributes to the generated component.
the only caveat is that if someone later supplies that same parameter when
invoking the component helper, it would override / shadow the value.
to avoid that, it could be passed in using a mangled name.
on my phone with a baby in one arm right now, so it's kinda hard to
elaborate more. :)
…On Sat, Jan 21, 2017, 5:39 PM Alex Matchneer ***@***.***> wrote:
@les2 <https://github.com/les2> I thought of something similar but got
stuck on the following: how would you pass in the closed-over scope?
{{title}}
{{#x-foo
header=(|data|
I too can access {{title}} via closed-over scope
(even if i hadn't previously referenced it
outside of this template block).
But if broccoli moved me to another file, how
would it have access to `{{title}}` (and `{{data}}`)?
)
/}}
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#203 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/ABBEYBlay00UMgUmQlgp3kmOc-VYeKBXks5rUokdgaJpZM4Lo9Em>
.
|
@les2 Ohhh so you're saying if I had a template block that looked like
Then the template block would be extracted verbatim into an anonymous component file and the above template would transform to:
I think that should actually work? That's really awesome if it does. @sclaxton how bout a bake off once the polyfill(s) come(s) together? Example of recursive nesting polyfil translation
turns into:
TL;DR the broccoli plugin would basically have to start |
@machty lets do this 😂 |
Gonna take a mental break from this RFC for a while, but got a polyfill working w the help of @sclaxton (based on @les2's idea) and got to try out a few things: This RFC has many warts and is likely incompatible a lot of the optimizations Glimmer has planned for static blocks (such that based solely on the syntax for rendering a component, the compiler should be able to know which blocks have been passed), but let this RFC serve as a representation of what might be possible with a more dynamic / attrs-based approach. |
There's something similar in Ember that already handles this use case: named outlet. It's the same idea. You have multiple slot/outlet in your template and you want to fill those slots/outlet with another template. You can do this as part of Another idea I had was about extending the {{#outlet "main" as |model queryParams|}}
{{/outlet}} |
@machty thanks for putting this RFC together. I stumbled into this by following my nose. Speaking from personal experience the nested template problem is something that many users might need but don't know how to describe the problem. It is amazing how many different implementations are out there solving similar but slightly different use cases. I would humbly submit that an important first step is some really clarifying examples or demo project showing why this RFC (and the others) is important. Need to see tangible working demos of the pattern put into practice. A hallmark of your previous efforts is the super cogent documentation, ala ember concurrency, and all those jsbins you created for query params. If feasible, it would be helpful to reference a comprehensive ember cli demo project. Hopefully this could even be a way to hone the api. Otherwise I fear a lot of ink will be spilled and many of us will still be confused. |
Thanks for the feedback @eccegordo; a lot of conversations have taken place since this RFC with the team working on Glimmer, and the present state of things is that something much closer to a "slot" / named block syntax is more likely to land. This proto-RFC has some details, and I recently presented at the Ember NYC meetup about the current state of things, and it's pretty out of sync with the ideas/direction of this RFC, so I think it's probably time to close. Rest assured there will be a million interactive examples as we get closer to the finish line. |
Rendered
By submitting feedback to this (likely to be controversial) RFC, you are implicitly agreeing to the statement below:
If you're interested in more real-time discussion of this RFC, head to the
#topic-forms
channel in the Ember Community Slack.