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鈥檒l occasionally send you account related emails.
Already on GitHub? Sign in to your account
[RFC]: au-slot, a replacement for the replaceable-parts #900
Comments
Very good, Just a question, Is it support conditional content projection with multiple slots? <button if.bind="someConditions">
<au-slot></au-slot>
</button>
<a if.bind="someOtherConditions">
<au-slot></au-slot>
</a> Use case: List group - Links and buttons <div class="list-group">
<a href="#" class="list-group-item list-group-item-action active">
Cras justo odio
</a>
<a href="#" class="list-group-item list-group-item-action">Dapibus ac facilisis in</a>
<a href="#" class="list-group-item list-group-item-action">Morbi leo risus</a>
<a href="#" class="list-group-item list-group-item-action">Porta ac consectetur ac</a>
<a href="#" class="list-group-item list-group-item-action disabled">Vestibulum at eros</a>
</div> And <div class="list-group">
<button type="button" class="list-group-item list-group-item-action active">
Cras justo odio
</button>
<button type="button" class="list-group-item list-group-item-action">Dapibus ac facilisis in</button>
<button type="button" class="list-group-item list-group-item-action">Morbi leo risus</button>
<button type="button" class="list-group-item list-group-item-action">Porta ac consectetur ac</button>
<button type="button" class="list-group-item list-group-item-action" disabled>Vestibulum at eros</button>
</div> |
I wonder if It can be more readable if the attribute is at the place of using the custom element, instead of in the implementation of the custom element. I changed the attribute to host-scoped since self-scoped is not suitable here. <my-element>
<div au-slot="s1" host-scoped>
Bye ${message}
</div>
<div au-slot="s2">
Hi ${message}
</div>
</my-element> |
One of the primary purposes of replaceable parts was to address the repeater scenario. In this case, the component developer has a repeat that is internal to the component, and provides a template for that repeat to generate from. They could then mark that repeat template as replaceable and then the consumer of the component could provide their own template, which would be injected into the component and used in place of its internal repeat template. Can you talk about how this proposal addresses this use case? |
@HamedFathi From the initial look, that use case can be supported. As far as I have understood that, there will be 2 different instructions, one for the @3cp I was also inclined towards removing this explicit control over scoping altogether. In that case, the inner scope will be used iff parent has not projected to that slot. I think the slot also works that way, as anything injected via light DOM gets bound to the outer scope. However, @EisenbergEffect has pointed out the repeater use case and in fact a prime use case of the <!-- au-grid with @bindable items -->
<table>
<thead>
<tr>
<au-slot name="header">
</au-slot>
<th>
Actions
</th>
</tr>
</thead>
<tbody>
<tr repeat.for="item of items">
<au-slot self-scoped name="content">
</au-slot>
<td>
<button>edit</button>
<button>delete</button>
</td>
</tr>
</tbody>
</table>
<!-- Usage -->
<au-grid items.bind="items">
<th au-slot="header">First Name</th>
<td au-slot="content">${item.FirstName}</td>
<th au-slot="header">Last Name</th>
<td au-slot="content">${item.LastName}</td>
</au-grid> However, the original definition of the <td au-slot="content">
<template if.bind="someConditionFromUsageVm">
${item.Prop1}
</template>
<template else>
${item.Prop2}
</template>
</td> And that is not a rare use case I would say. From this perspective, we ca define the I can update the original post if we agree on this. |
Love the repeater use case. Gonna use it. |
I am think we might not need self-scoped to support this use case. What about for au-slot to introduce an extra layer of overrideContext? Just like a normal template controller does. User writes expressions to access their local things, but can access the host element's scope with context variable This can solve your dynamic use case. It also makes user code very explicit without ambiguity. |
I got an interesting example. <repeater-a>
<let outer="$host"></let>
<repeater-b>
${outer.item.foo} ${$host.item.bar}
</repeater-b>
</repeater-a> |
I like it as well. A lot, actually. |
This thing has to a keyword in parser in au2 now? |
Nothing changed there.
However, It doesn't, because that gives you the root bindingContext that is the viewModel of the owning element. What you need is the immediate binding context of the declaring side (which might be multiple levels of synthetic binding contexts deeper, if there are template controllers in-between) and from there on travel further upwards up until the element boundary. In addition to that, if slot content ends up being distributed into a slot that is itself also slot content for another slot, you need to skip over a scope boundary, etc, etc. |
This feature should work in both au-slot and slot, right? |
Updated the RFC: the scoping examples with $host and added the repeater example. |
I don't quite understand the repeat example. It seems like there will then be multiple instances of the "content" slot, which would seem invalid. It certainly is with native slots. Also, replaceable was designed to replace the entire template of a repeater/if/etc with a completely new template. This would mean replacing the entire |
@EisenbergEffect You are right. When you compare this with slots then that example is not valid in context of repeater, as that would mean the same slot is being defined multiple times. However, I was hoping that BTW a very similar variant of the repeater example, I gave earlier, works in Au1. For my particular use case, I need the partial replacement of the |
That is kind of the goal though, in order to become less confusing. Maybe that's not what we want to name it per se, but it should be able to work as native slots do. To quote an example written by @davismj in 2016 here: http://www.foursails.co/blog/semantic-template-parts/ v1:<template class="ui accordion">
<template repeat.for="item of items" part="item-template">
<div class="title" part="title-template" replaceable>
<i class="dropdown icon"></i>
${item.title}
</div>
<div class="content">
<template part="content-template" replaceable>
<p>${item.content}</p>
</template>
</div>
</template>
</template> v2:<template class="ui accordion">
<au-slot repeat.for="item of items" name="item-template">
<div class="title" name="title-template" as-element="au-slot">
<i class="dropdown icon"></i>
${item.title}
</div>
<div class="content">
<au-slot name="content-template">
<p>${item.content}</p>
</au-slot>
</div>
</au-slot>
</template> As a side note specifically on the topic of the table elements, |
Although that is a valid example, I think making the repeater root replaceable is a very rare use case. For a reusable component, I don't see one want to replace the repeater root. One use-case might be that a 'list' CE is written with a table layout, but during use a Having said that, the example shows an interesting use-case. |
馃挰 RFC
This RFC proposes an alternative and enhanced syntax for replaceable parts. It necessitated from the need of emulating the native slots to allow CSS penetration. See #654, and #898. However, emulating slots based on global, and custom-element-level configuration brings its own set of complications in terms of templating, binding, and managing scopes. Apart from that, the idea of emulating slots, feels going towards opposite direction of Aurelia's spirit of keeping things closer to the native behavior.
With that spirit, this RFC proposes not to emulate slot at all (hear me out 馃槂) and rather provide an alternative syntax to support the actual use cases. From a practical standpoint, deciding whether a custom element is going to use slot/shadow DOM or not is a non-trivial decision, as the custom element needs to be styled accordingly. That is almost always a non-trivial task in a real-life application. Therefore, the assumption that a flag can be set to emulate or provide native behavior is bit impractical.
馃敠 Context
In Aurelia2 new syntax of
au-slot
is being proposed instead. This provides slot like behavior but with CSS penetration. From this perspective it is similar to replaceable-part syntax. In factau-slot
is proposed to be an enhancement over replaceable-part with the addition of controlling the binding scope. Moreover, it explicitly points out that devs are not using the native slot, and therefore there is no question of emulating the same.馃捇 Examples
Example#1: Simplest case with any number of content from the custom element as well as an optional default and any number of named 'slot's.
my-element.html
my-app.html
This produces loosely the following output.
Example#2: Controlling binding scopes with
$host
.my-element.ts
my-element.html
my-app.ts
my-app.html
This produces loosely the following output.
Scoping rules in a nutshell:
$host
is used in the expression. the traversal starts with the inner scope.$host
is not used) the parent scope is used for binding.Check this example out.
Example#3: Repeater
馃搩 Summary
replaceable
does not support projecting multiple roots to a single slot. In case of the example#1,replaceable
would have projected only<div>this goes to slot s1 as well</div>
.au-slot
in place, thereplaceable
template controller and the replace parts can be removed altogether.replaceable
where the inner scope is used for binding, and the parent scope is only traversed if the property is not found in inner scope.Let me know your feedback on this.
Edits
$host
and added the repeater example.The text was updated successfully, but these errors were encountered: