Skip to content
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

[Feature request] Whitelisting which components can render within a block component #121

Closed
olivierlesnicki opened this issue Feb 15, 2016 · 12 comments

Comments

@olivierlesnicki
Copy link

It looks like the framework doesn't support a default way of whitelisting which components can render within its yield.

{{#parent-component 
  as |first-child second-child|
}}
  {{first-child}}
  {{second-child}}
  Hello World.
{{/parent-component}}

The requirement is to be able to render {{first-child}} and {{second-child}} because they're components supplied by the parent-component but not render "hello world." or any other component/data for that matter.

A workaround is today's possible with ember-wormhole where the parent-component can have the following template:

// parent-component
<div id="first-child">
</div>
<div id="second-child">
</div>
<div style="display:none;">
  {{yield}}
</div>

And the first-child:

// first-child
{{ember-wormhole to="first-child"}}
  ...
{{/ember-wormhole}}

While it does achieve the required requirement I think it's important for a framework that offers composability to be able to handle.

Because react requires you to define the template within the render hook you're able to do it quite easily:

render() {
  return (
   <div>
     {this.props.children.filter(child => {
        return child instaceof FirstChild || child instanceof SecondChild;
     })
   </div>
  );
}

Maybe there's a way to do it which I wasn't able to find on StackOverflow nor ember set of documentation.

(originally raised emberjs/ember.js#12968)

@rwjblue
Copy link
Member

rwjblue commented Feb 15, 2016

What is the actual use case here? It seems odd to attempt to limit the consumer of your component like this...

@olivierlesnicki
Copy link
Author

To reply to @rwjblue comment on emberjs/ember.js#12968 (comment)

Here are a few examples I think could have benefited from this pattern:

A "navBar" component, that can only have "button" and "title" components. As the component's developer being able to only whitelist btn and title makes sure I have an integral control on the component's render state (ie. styles).

{{#nav-bar as |btn title|}}
  {{btn icon="hamburger"}}
  {{title}}Hello World{{title}}
  {{btn icon="paper-plane"}}
  {{btn icon="search"}}
  Hello World. <-- This should not render!
{{/nav-bar}}

While this example demonstrate a purely "aesthetic" consideration, I've encountered multiple cases where I wanted to whitelist the elements being render for functional purposes.

For example: a horizontal-item-scroller component. In my specific case I'm using an external library to align elements within a carousel. These elements require specific class and tag names to work correctly. Therefore I'm introducing composable components that abstract setting these attributes on the element.

Adding an element that doesn't follow this API actually brakes the whole carousel (it's no better than not showing it)

{{#horizontal-item-scroller as |item big-item|}}
  {{#item}}Render this{{/item}}
  {{#big-item}}Render this{{/big-item}}
  {{#whatever}}Don't render this{{/whatever}}
{{/horizontal-item-scroller}}

@tomdale
Copy link
Member

tomdale commented Feb 15, 2016

I don't think it makes sense to add this to the core framework, but I am definitely interested in exposing the hooks necessary to make this possible from an addon.

@olivierlesnicki
Copy link
Author

@tomdale do you have a vague idea of which hooks could be leveraged to achieve this result? Even if they're private - for research purposes.

@ef4
Copy link
Contributor

ef4 commented Feb 15, 2016

If you really want that level of control, I would suggest not yielding. Yielding implies giving up control over what goes inside, and is why it's called "yield".

A nav bar that wants to define a restricted API can do so via it's own arguments, including taking components (with bound arguments and everything) as arguments, like:

{{nav-bar items=items button=(component "fancy-button" mode="wonderful") }}

@olivierlesnicki
Copy link
Author

@ef4 I think attributes works OK when the number of arguments can be kept at a minimum level. It's not always possible. Imagine a jQuery.masonry wrapper that requires children elements to be wrapped inside specific elements (as that's the only way for them to be positioned correctly).

{{#masonry
  as |masonry-item|
}}
  {{!-- can have many, many, many of them !--}}
  {{#masonry-item}}
    Hello World.
  {{/masonry-item}}
{{/masonry}}

While I understands what yield does and why it was called like that, I don't think it's a strong enough argument against challenging its limits. It's not because it's named one way that we should never attempt to touch it nor question it.

Composable components are offering developers a great way to define declarative API. I'm sure they're only going to grow in popularity (especially when you see what the guys achieved with https://github.com/reactjs/react-router) and new patterns will emerge. I think exposing the relevant hooks for developers to be able to build upon it is a step in the right direction.

@mmun
Copy link
Member

mmun commented Feb 15, 2016

Contextual handling of HTML/components has been anticipated by Glimmer, but still needs a long time to bake and it's not clear we want the feature at all as it complicates the mental model. The idea is to enable things like

<super-layout>
  <row> ... </row>
  <row> ... </row>
  <div> </div>     {{! this could throw a compile time error }}
  foo              {{! so could this }}
</super-layout>

The feature would have a similar spirit to the <table> element in HTML and its contextual handling of <thead>, <tbody>, etc.

@olivierlesnicki
Copy link
Author

@mmun where is it possible to follow the progress on this one?

@rwjblue
Copy link
Member

rwjblue commented Feb 16, 2016

It should be possible to do this sort of assertion today via at least two mechanisms (possibly more):

  • check the DOM in didInsertElement for development builds (via Ember.runInDebug), and throwing/asserting if you find malformed contents (this is public API)
  • write an AST transform that runs at template compile time, and asserts when invalid content exists (AST transforms are private API)

@olivierlesnicki
Copy link
Author

@rwjblue thanks

kategengler pushed a commit to kategengler/rfcs-1 that referenced this issue Dec 21, 2018
[RFC] Replace ember-cli-eslint with the standard eslint
kategengler pushed a commit that referenced this issue Jan 19, 2019
[RFC] Replace ember-cli-eslint with the standard eslint
@mehulkar
Copy link
Contributor

mehulkar commented Apr 1, 2020

@olivierlesnicki I think this is superseded by #454 ?

@locks
Copy link
Contributor

locks commented Jun 28, 2022

Closing!

@locks locks closed this as completed Jun 28, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants