-
Notifications
You must be signed in to change notification settings - Fork 546
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
Proposal for new slots syntax #2
Conversation
I had doubt about the shorthand syntax being invalid attribute name but HTML spec is very flexible. Any printable charcter except ( |
Is this valid syntax? <foo>
<template :(dynamicSlotName)="{ name }">
<div>Hello {{ name }}</div>
</template>
</foo> |
@znck I'd avoid that if I can. If you need that level of dynamism you probably should go render functions directly. Edit: supporting it is not that difficult. The downside is dynamic slot names means the slots generated will not be "stable" and can require some optimizations to bail out. |
The <foo ()="foo">
<bar ()="bar">
<baz
()="baz"
@close="() => isVisible = false">
{{ foo }} {{ bar }} {{ baz }}
</baz>
</bar>
</foo> I like the However,
|
The reasoning behind using Also, it's better to use an inline expression instead of arrow function for events. |
@znck you are right for events. Although it is not uncommon to see function properties that are not events which evaluate immediately, but still need to pass in properties from the template through an anon function. So a more common usage case would be something like: <foo ()="foo">
<bar ()="bar">
<baz
()="baz"
:onBaz="() => someMethod(baz)">
{{ foo }} {{ bar }} {{ baz }}
</baz>
</bar>
</foo> However, it is not lost on me that the component author could implement
Ah I see, I wonder if the fact that you cannot pass in any arguments is also what is trippy. It's a function underneath but |
I love this idea:
Sample: <foo &="{ foo }">
<bar &="{ bar }">
<baz
&="{ baz }"
:onBaz="() => someMethod(baz)"
@input="() => otherMethod(bar)"
>
{{ foo }} {{ bar }} {{ baz }}
</baz>
</bar>
</foo> Or: <foo v-scope="{ foo }">
<bar v-scope="{ bar }">
<baz
v-scope="{ baz }"
v-bind:onBaz="() => someMethod(baz)"
v-on:input="() => otherMethod(bar)"
>
{{ foo }} {{ bar }} {{ baz }}
</baz>
</bar>
</foo> |
I think having a scoped slot and an expression that contains an arrow function is quite rare (it's definitely possible, but also definitely not common). BTW - in React callback props and render props all use arrow functions and it doesn't seem to be an issue. On the other hand, this can actually be solved at the syntax highlighting level (the parens will be colored differently). My personal reservation against |
Square brackets could be used to avoid confusion with Angular props and arrow functions. <foo []="foo">
<bar []="bar">
<template [header]>
123
<template>
<template [footer]="{ baz }">
{{ foo }} {{ bar }} {{ baz }}
</template>
</bar>
</foo> |
This is not HTML compliant at all but I find this way of defining slot and scope props interesting: <foo="foo">
<bar="bar">
<template:header>
123
</template>
<template:footer="{ baz }">
{{ foo }} {{ bar }} {{ baz }}
</template>
</bar>
</foo> |
v-scope says nothing about what is. how it's look with named slots? <bar>
<template slot="header" v-scope="{ foo }">{{ foo }}</template>
</bar> in the form of (in) => <Out>{in}</Out> But in our case, the brackets point to the correct slot, and then pass it inside. const { out } = (slot)
<tempalte>{{ out }}</template> This is similar to react render props and not at the same time. In my opinion
|
Why a shorthand might not be appropriate for scoped slots@yyx990803 I generally like the direction this proposal is going, except for the shorthand. I agree with @c01nd01r that at first glance,
Both
Other limitations of this proposal
An alternative idea:
|
I appreciate the input but I find the
Sidenote: I think we should refrain from coming up with completely different proposals under an RFC to avoid sidetracking. Separate proposals aimed at solving the same problem can be submitted as a separate RFC so it gets its own dedicated discussion. |
Maybe the shorthand could be phased out of the proposal and we can make another RFC to discuss it? |
In response to concerns raised by @chrisvfritz regarding the original proposal: Usage of
|
For reference: shorthand syntax comparison Btw @CyberAP -
|
I really like the hash # for 2 reasons:
|
Why not allow shorthand on normal elements? When using shorthand there is no ambiguity: <parent>
<foo
(header)="parentSlotProps"
()="defaultSlotProps"
>
...
</foo>
</parent> |
@dima74 because then |
Would love to get a sentiment on the general reception of the shorthand here... Please vote:
|
If we choose to go with directives, using directive args is definitely a better choice than creating another micro syntax inside attribute values IMO. The only inconsistency here, like what @chrisvfritz proposed for multiple |
|
Like @darrenjennings 's idea for use & as shorthand syntax. |
@yyx990803 can you add an example where both the default and name slots are used? I guess it would look like this: <foo>
<template ()="one">
{{ one }}
</template>
<template (two)="two">
{{ two }}
</template>
<template (three)="three">
{{ three }}
</template>
</foo> While trying to get to the above example I created this version too which probably a mistake and won't work: <foo ()="one">
<template (two)="two">
{{ two }}
</template>
<template (three)="three">
{{ three }}
</template>
</foo> |
I agree with @dccampbell, I voted against a shorthand because not a lot of keystrokes are saved and makes it potentially more confusing for beginners (and scoped slots/'slots with props' are quite confusing to begin with).
It kind of looks like you're assigning a value to a slot but actually you receive something to use for your slot. Conceptually it's more like
or like
|
@murr4y A shorthand isn't useful just for saving a few strokes, for me it helps to easily scan the code and understand what's going at a glance. It seems this discussion is focused on the shorthand more than the actual proposal, but I think it's important and giving it its own symbol will encourage using scoped slots. |
@Nandiin your example of nested default slots vs. nested named slots is a considered tradeoff, because the former is in practice more commonly seen than the latter. I'd also argue the new syntax in this case, while being more verbose, is easier to read and understand. |
I've taken some code from a tutorial on using dynamic named slots I was working on and would like to rebuild it with the new proposal to see if I understand it. The idea of the code below is to build different types of survey questions using the dynamic named slots feature. It is also using Quasar Framework btw. <!-- old -->
<!-- this is the questions component code -->
<template id="questions-template">
<div>
<div v-for="question in questions" :key="question.id">
<slot name="text" :text="question.text"></slot>
<slot :name="question.id" :input="question.input"></slot>
</div>
</div>
</template>
<div id="q-app">
<p class="caption"><strong>{{ title }}</strong></p>
<questions-component :questions="questions">
<div slot="text" slot-scope="{ text }">
{{ text }}
</div>
<template v-for="question in questions"
:key="question.id"
:slot="question.id"
slot-scope="{ input }"
>
<q-field :helper="input.help">
<component v-if="input.type === 'input'"
is="q-input"
v-model="input.value">
</component>
<component v-if="input.type === 'select'"
is="q-select"
v-model="input.selection"
:options="input.options">
</component>
<component v-if="input.type === 'multi-select'"
is="q-select"
v-model="input.selection"
multiple
:options="input.options">
</component>
</q-field><br/>
</template>
</questions-component>
</div> <!-- New -->
<!-- this is the questions component code -->
<template id="questions-template">
<div>
<div v-for="question in questions" :key="question.id">
<slot name="text" :text="question.text"></slot>
<slot :name="question.id" :input="question.input"></slot>
</div>
</div>
</template>
<div id="q-app">
<p class="caption"><strong>{{ title }}</strong></p>
<questions-component :questions="questions">
<div v-slot:text="{ text }">
{{ text }}
</div>
<template
v-for="question in questions"
:key="question.id"
v-slot:[question.id]="{ input }"
>
<q-field :helper="input.help">
<component v-if="input.type === 'input'"
is="q-input"
v-model="input.value">
</component>
<component v-if="input.type === 'select'"
is="q-select"
v-model="input.selection"
:options="input.options">
</component>
<component v-if="input.type === 'multi-select'"
is="q-select"
v-model="input.selection"
multiple
:options="input.options">
</component>
</q-field><br/>
</template>
</questions-component>
</div> Is this correct? Dynamic slot names weren't mentioned in this RFP, but would that be how they might work? ( and please do keep them! 😃) Scott |
@smolinari See #4 |
@Akryum - Thanks. I missed that RFC completely. 😊 But, it seems I got it right. 😁 Scott |
@smolinari the new syntax requires |
Aha! Ok. Thanks for the clarification Evan. Scott |
Am I late to the party? Can't the Named Slots: And use attributes to get the variables into the slot scope: For scoped slots (just like in |
Would it be possible to output the same slot to multiple named slots? For example the select component provides customization for dropdown item and displayed selected item via different slots, and the developer wants to use the same template for both? |
@donnysim great idea 👍 I've had that usecase come up before, and had to resort to create a local component to contain that. For those trying to understand the use-case better: take a look at select2's documentation: http://select2.github.io/select2/ Could we maybe allow two of them on the same element? <beefy-select>
<div #selection="item" #result="item"></div>
<beefy-select> And then behind the scenes, the compiler would assign that to both functions. |
@JosephSilber - just remember, with this change, named slots must be within a Maybe it could work this way too??? <beefy-select>
<template #[beefySelectSlots]="item">
<div></div>
</template>
<beefy-select> and in the code export default {
data () {
return {
beefySelectSlots: ['selection', 'result'],
.... In other words, if the slot's name argument is just a string, there is only one slot to fill. If it's a dynamic named slot and the argument is an array, then there are multiple slots to fill. That would make this really flexible. Adds to the complexity though. 😄 Scott |
But then inline would look like <beefy-select>
<template #[['selection', 'result']]="item">
<div></div>
</template>
<beefy-select> ? I don't really like having to declare a variable just to pass multiple slots, it just feels disconnected when viewing the template. I'm hoping that at least this: <beefy-select>
<template v-slot:selection="item" v-slot:result="item">
<div></div>
</template>
<beefy-select> is feasible or any other syntax, as long as it makes it possible without having to leave the template. |
Well, I can't disagree with you and in fact, I was going to ask if this might be possible.
But, I seemed to remember reading somewhere that spaces in the argument like that wouldn't be possible. Thus, why I suggested the variable/ array. I guess we'll have to wait until Evan can chime in on this. Scott |
@smolinari oh yeah, true, true, I totally forgot about spaces. |
This comment has been minimized.
This comment has been minimized.
@pxwee5 this is an implementation bug, please open an issue in the core vue repo instead of commenting on the RFC. |
Was clarifying if it's a bug or not. |
@smolinari, your proposal, unfortunately, would break all compatibility with pug (see this part), the loader for which (pug-loader) already struggles with the current shorthand syntax ( |
It is too bad (that I am too late in bringing this up, as it wasn't until trying out the new syntax), but there are issues (most likely previously discussed elsewhere) with putting slot names/vars in the attribute name. A few key issues are (that really limit the flexibility of scoped slots with the new syntax):
A better approach (in my opinion), would have been to break the new syntax in two: <!-- pass a string literal as the slot name (needs quotes, just like regular directives) -->
<!-- preserves case, spacing, special chars, etc, in slot name -->
<template v-slot="'slotName'" v-scope="{ some, props, here }"></template>
<!-- pass a variable containing the slot name, case sensitivity of the variable is preserved -->
<template v-slot="someVar" v-scope="{ some, props, here }"></template>
This gets around all the limitations with attribute names (spaces, case sensitivity not guaranteed, etc), while keeping the attributes as custom attributes (i.e. hyphenated, prefixed with A shortcut syntax could still be employed, but may not be so short... maybe the shortcut could be as is in The other option is to not to deprecate the old Another alternative would have been to create a special Vue built-in component (say Summary: The current 2.6+ cc/ @yyx990803 @posva |
Where I can find official specification about new v-slot naming convention (e.g. for naming with more than one word)? And why new specification (v-slot:slotname) is not compliant to xhtml (v-slot="slotname")? |
* Dynamic Routing * precision from * add getRoutes * add alternative for getRoutes * fix: typo in 0000-router-dynamic-routing.md (#1) * fix typo (#2) * Update 0000-router-dynamic-routing.md (#3) Just some grammatical corrections. Hope you don't mind. Scott * remove template drawbacks * update * rename Symbol to symbol, type typo * rename Co-authored-by: pierresaid <said.pierre.emler@gmail.com> Co-authored-by: atilkan <emrahatilkan@gmail.com> Co-authored-by: Scott <smolinari@users.noreply.github.com>
Rendered