Closed RobbieTheWagner closed 9 years ago
+1 for this. I ran into a similar use case. I'm not sure whether it is semantically correct to inherit the template. I worked around it by specifying the layout name for the child component and rendering it as a block.
@rwwagner90 This seems pretty unlikely to be adopted- Overriding how and where a component {{yield}}
s is very much something a child component (via inheritance) would want to do. IMO you want a way to call {{super}}
from a template to accomplish what you want here.
But templates play absolutely no role in the inheritance flow right now, and making them aware of it is a rough sell. Hm.
@mixonic it just seems counter intuitive to me to not be able to do some sort of inheritance. If I have a parent component that has a lot of common functionality and DOM elements, I obviously want to have my child component extend it for the JS functionality, but then there is no provision for pulling in the common DOM from the parent template, unless you use partials, which blows away the point of the component inheritance or actually use component blocks, which forces you to duplicate code.
I've managed to get the behaviour you're describing working.. I'm not sure I would recommend it and I'm likely going to move away from it in favour of tagless components.
I achieved this by setting the components layout
property to the parent component template, and the template
property to the child (current) component.
If you're using Ember CLI with pod structure there is a particular way to get this to work. Basically when a component is resolved Ember will try find the template.hbs
file - once that's found it uses that template as the layout
property - completely ignoring if you've explicitly set a layout
property on your component.js
- you need to trick Ember by calling the child component template something other than template.hbs
Anyway I'm not sure I've explained it well enough - but if I haven't then I have an example that might help. I've previously logged this as an issue with Ember CLI (https://github.com/ember-cli/ember-cli/issues/3496) - in this issue there is a link to a repo (https://github.com/jmurphyau/component-template-issue) which shows how I got the inheritance to work.
The layout represents a components shadow dom. The template is the "light" dom, of the contents of yield that gets rendered in the outer scope. I definitely don't think that is a viable long-term solution, and may have some weird edge cases.
So let's assume for a minute that I have an inheritance chain like parent -> child -> child -> child. What would be the recommended way to use all the common elements from each level in the final child component? It would make sense to me to have some way to have the templates work together.
@rwwagner90 a compiled template is just an object stored on a property. Like any other property on an instance, there is no way to arbitrarily yank parts of an object you've replaced from a superclass at the same property.
I think I suggested a fairly viable idea with {{super
but the implementation and ramifications across apps are unclear (like in init
, do you always call super just in case you have a parent? Seems onerous).
I hope you agree there isn't a trivial solution and the problem will require a lot of thought and api design work.
Yeah, I definitely don't think there is a trivial solution. There are some "easier" solutions, but they could have bad implications. I'm not sure how to get this right, but I think it would be very useful to have. Changing everything over to components, but then still requiring you to use partials because this isn't supported just feels incomplete to me. I realize this may not be implemented anytime soon, but do you agree there is a need there @mixonic?
Could you do something like this:
child-component/template.hbs
{{#parent-component}}
This is the child component
{{/parent-component}}
parent-component/template.hbs
{{#grandparent-component}}
This is the parent component
{{yield}}
{{/grandparent-component}}
grandparent-component/template.hbs
This is the grandparent component
{{yield}}
That outputs the HTML below when calling {{child-component}}
<div id="ember434" class="ember-view grandparent parent child">
<div id="ember441" class="ember-view grandparent parent">
<div id="ember446" class="ember-view grandparent">
This is the grandparent component
This is the parent component
This is the child component
</div>
</div>
</div>
This was/is a problem for me and this is where tagless components are have an advantage - if the {{grandparent-component}}
and {{parent-component}}
both have tagName: ''
you only end up with one div:
<div id="ember434" class="ember-view grandparent parent child">
This is the grandparent component
This is the parent component
This is the child component
</div>
@jmurphyau we did consider an option along those lines, but won't wrapping each of those like that cause us to have to pass variables back up the chain to the grandparent component?
I would expect so - yeah.
I'd like to avoid having to do that. There may not be a way around it though. Just would really like to see this implemented. Would be very slick.
They may be good to explore in an RFC or RFC issue, as this appears as a feature request not a bug report.
@stefanpenner what should I do to start the discussion in a more appropriate place?
@rwwagner90 Make an issue (not a PR) on the RFCs repo emberjs/rfcs and gather feedback. I'm interested in seeing actual use cases rather than foo and bar. We should have this discussion ASAP so the feedback can be taken into account for the work on angle bracket components.
@mmun I made an issue in rfcs. https://github.com/emberjs/rfcs/issues/77
It's been awhile since I had an actual use case for this, but I'll try to come up with a better example than foo and bar.
hello, I am running into an issue where I have a parent route and I want the template to have some default content, but render over that with a child route.
Example:
import Ember from 'ember'
import config from './config/environment'
Router = Ember.Router.extend
location: config.locationType
Router.map ->
# Channels
@route 'channels', path: '/', ->
@route 'channel', path: ':slug', ->
# Content
@route 'content', path: ':slug'
export default Router
# templates/channels/index.hbs
<main class="main channels container-fluid">
<div class="row">
<h1>The brown fox jumped over the...</h1>
{{#outlet}}
<p>Here I am, the content for my cool component that displays within the parent index view.</p>
{{/outlet}}
</div>
</main>
# templates/channels/channel.hbs
<p>Here I am, the content for the child route/template</p>
Is this possible? it seems to touch in template inheritance which is how I found this issue... Is there any way to achieve this currently?
I think something like this should be supported, especially with the push towards components.
I want to have a parent component with a template like:
And then I would expect for child components, that extend that parent component to just be able to define a template of:
And have it automatically put that in the yield, so whenever I used the child component, it would show up as: