tko
tko copied to clipboard
Add support for "slots"
I would be impressed if done right.
I thought it was what web component people call "transclusion". Not sure any more after Googling.
In Angular the slot name is substituted with a sort of css selector applied on the component inside content.
https://scotch.io/tutorials/angular-2-transclusion-using-ng-content
+1 over here.
Seems like it wouldn't be too tough unless I'm missing something about this. Basically just allowing components to define a template within their inner HTML that binds to the $data. which then is injected into the template wherever the slot occurs. Honestly, we've built lots of components this way in knockout with a simple
<!-- ko template {name:'component-body-template',data:$data} -->
<!-- /ko -->
in the template for the component. This would allow the template to be dynamic (as the body of the custom element) and not have to be defined and named separately. We do this all over our code currently, and it works great. Most of those templates are only used once, which creates lots of structure and mess that could be simplified in this approach.
I imagine the slot implementation could be as simple as adding $innertemplate or something to context whenever component binding is invoked. Then anywhere within the component there could be a
<ko-slot></ko-slot>
which just binds up the $data to $innertemplate. That could allow some interesting and useful scenarios in a very web-component-ish manner.
There is similar functionality in Durandal called Widgets if you want to review more variations of the same theme. Please, keep this functionality optional, so that it is possible to exclude this module if not needed (or any other impelmentation is desired).
This is already supported in Knockout to some degree: http://knockoutjs.com/documentation/component-custom-elements.html#passing-markup-into-components
If I understand well, it might be trivial to write a new binding à la <!-- ko slot: selector --><!-- /ko -->
which would work like a <!-- ko template: { nodes: $($componentTemplateNodes).find(selector).get() } --><!-- /ko -->
To me the one specific thing that vue does is which is really powerful is use the slot attribute of a template - presumably keeping the templates in a manner where component templates cannot contaminate each other. At present, we use lots of <template>
in our SPA application, and have occasionally found uniqueness issues across the team. That would be the benefit to the slot approach over the currently available approach @mbest mentions.
Also, wondering how hard it'd be to enable named slot defaults in the registered component as well? I'm thinking done in such a manner that a default "slot template" is provided, but each slot could be overridden per-component instance.
I think those 2 benefits:
- Encapsulation of set of names per component
- Provide default and override capability per slot
would be a great add to the story of using tko components as a web-component framework.
@rposener What I linked to doesn't require <template>
tags. It's the same functionality as a basic <slot>
(without names).
I've implemented slots, and they look like this:
When creating a component named <custom-component>
with the following template:
<template id='custom-component-template'>
One
<slot name='abc'></slot>
Two
</template>
We can use the custom component:
<custom-component>
<template slot='abc'>Slot!</template>
</custom-component>
Which will output:
<custom-component>
One
Slot!
Two
</custom-component>
There are some lingering questions, but this is the first run at it, and the specifics should improve/hone with time.
I'd say the ideal approach here is to just use components as parameters, which is the react model. That might be better than creating a new concept to learn.
Is there a clear example of that somewhere?
Sure, here's an example article I found - https://jaketrent.com/post/ways-to-compose-react-components/#components-as-props
@daedalus28 Thanks for the link and input.
I've reviewed the two front-runner options, namely React and Vue, and the Vue model for slots seems more in-line with the KO model. Replicating what React does would require a relatively substantial investment by comparison, and even then I anticipate some kinks, so — notwithstanding input that illuminates any ignorances I have on this — I'm going to stick with Vue's <slot>
model.
So what we end up with for transclusion will be familiar to people who use Vue, and perhaps less familiar to those with a React background.
Did this ever get implemented? cannot find any reference to slots in documentation anywhere.
@grofit It is implemented, but not documented. The unit tests verifying the behaviour are here:
https://github.com/knockout/tko/blob/master/packages/binding.component/spec/componentBindingBehaviors.js#L1019-L1430