Open Sinjhin opened 7 years ago
Reasons to use plain attribute name (context='this'
, context='doSomething(a,b,c)
:
{^toParent}
and ({two-way})
probably don't make senseReasons to use curly attribute name ({context}='this'
, {context}='doSomething(a,b,c)
:
Maybe {^toParent}
and ({two-way})
could make sense?
<email-editor>
<can-template name="subject">
<input type="text" {($value)}="this"/>
</can-template>
</email-editor>
<!-- email-editor.stache -->
<can-slot name="subject" {(context)}="subject"/>
or even using to-parent:
<email-editor>
<can-template name="subject">
<input type="text" {($value)}="this"/>
</can-template>
</email-editor>
<!-- email-editor.stache -->
<can-slot name="subject" {(^context)}="subject"/>
I don't think it would be a good idea to add context to a can-slot. This takes power away from the developer that is implementing the slot to define their own context and gives it to component that is slotting it. If the component needs to have control over a subtemplate then passing the template through normal methods (like the component's own attributes) is more appropriate.
@matthewp I think you might have it backwards. The developer implementing the slot has control over the context the can-template
element provides.
I can't find any code that references can-slot
or can-template
in can-component. Where can I learn more about this feature so that i can understand it better?
@matthewp look at https://github.com/canjs/can-stache/pull/209 and https://github.com/canjs/can-component/pull/103
There are docs in progress here: https://github.com/canjs/can-component/tree/4-can-slot/docs
It's a pretty common ask to want some of the data on the view-model available to the "user dom" (this is why can-component
had leakScope: true
by default at first).
Say I had an autocomplete that looked like:
VM = DefineMap.extend({
query: "string",
get resultsPromise(){
return Search.getList({query: this.query});
}
})
Component.extend({
ViewModel: VM,
view: `<input .../>
<ul>{{#each resultsPromise.value}}<li>...{{/}}</ul>`
})
If we want to let people customize the search results, we need to be able to pass the search results back to them. context
(or as I show {this}
) would allow us to pass the search results like:
<auto-complete>
<can-template name="results">
{{#if this.isPending}} Loading ... {{/if}}
{{#each this}}<div>....{/}}
</can-template>
</auto-complete>
Implemented as follows (with default search results):
Component.extend({
tag: "auto-complete",
ViewModel: VM,
view: `<input .../>
<can-slot {this}="resultsPromise" name="results">
<ul>{{#each resultsPromise.value}}<li>...{{/}}</ul>
</can-slot>`
})
Ok, I think I understand the feature now and rescind my previous objection. I think this is blurring the lines between component API and stache a bit much though.
@matthewp why do you think that? There is a bluring as can-stache
needs to be aware of <can-template>
in a similar way as can-stache is aware of custom elements. I think it's ok for can-stache
to provide some low level custom-element fundamentals similar to how the DOM might provide <slot>
s.
Another alternative, which might have been what you were thinking is for <can-template>
to be able to "steal" values from the viewModel
:
<auto-complete>
<can-template name="results" {^search-results-promise}="*searchResultsPromise">
{{#if *searchResultsPromise.isPending}} Loading ... {{/if}}
{{#each *searchResultsPromise}}<div>....{/}}
</can-template>
</auto-complete>
I don't like this as much. I look at <can-template>
as mostly a way to pass a renderer to a can-component. I look at {this}
or {context}
as a way to specify an argument that gets passed to that argument.
Effectively:
var component = function(renderer) {
renderer(CONTEXT);
}
component( myRenderer )
I don't think this is low-level though. It's providing an alternative syntax for executing a function. You can already execute a template in stache like so:
light
<my-element {childtmpl}="someTemplate"/>
my-element template
{{childtmpl(someContext)}}
I don't have a problem with can-component reaching in to its light-dom and building up this .templates
thing, I just don't see why there needs to be a second way within the language to execute a renderer function. I can see the advantage of the (arguably) nicer syntax but that can be done in userspace through custom elements.
@matthewp how could be done in userspace? <content>
is basically the same thing (implemented almost exactly the same) and can't be done in userspace.
To summarize my opinion: I think it's a good idea to separate slotting and hydrating. Otherwise, how could I do something like pass a can-template to another element?
@matthewp how could be done in userspace?
is basically the same thing (implemented almost exactly the same) and can't be done in userspace.
So, assuming that this.templates
within the component refers to the light dom can-templates:
Component.extend({
tag: "my-element",
events: {
inserted: function(){
this.viewModel.templates = this.templates;
}
}
})
(maybe there should be an option for can-component to do this for you?)
{{templates.sometmpl(someContext)}}
If that works, and it should, then building higher level constructs like a custom element that takes a context and a template and executes that template should be trivial.
@matthewp yeah, I've thought about this, but it's so heavily "view" related, that I avoided it (which might require people creating a templates
property on their VM
).
Perhaps for can-element
we can create a view
or templates
property automatically on the element?
It would be good to add context to
<can-slot>
s.This could look like
<can-slot name='subject' context='this' />
or<can-slot name='subject' {context}='this' />
or<can-slot name='subject' context='doSomething(a, b, c)' />
Using the curly brackets for binding is up for discussion.
Things left to do: