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

Handlebars helper or component that yields inside a specified outlet anywhere in the hierarchy #28

Closed
kzgolden-pba opened this issue Jan 17, 2015 · 14 comments

Comments

@kzgolden-pba
Copy link

My use case is as follows:

I have a dialogue that will manipulate passed in data which I want to make into a component. The dialogue would be a triggered by a button, which would open the dialogue in a "modal" outlet which lives at the application level, and is used all over the application when a modal/popup is desired.

I would like the button and dialogue to belong to the same component so everything can be self contained and I don't have to do things like create a special action on the route every time I want to use the dialogue/button combo. This way, I can just insert the component into the template where I want the button to appear, pass in the data and not have to do anything outside of the component.

I implemented a jsbin kind of hacking my way through what I wanted:

http://emberjs.jsbin.com/wavepo/6/edit?html,js,output

I also mentioned this to @wycats and @rwjblue in IRC where content_for from Rails was brought up, as well as a helper/component that could be placed into a component (or view) template in order to yield some content into a target outlet:

{{#fill-outlet "someOutsideOutlet"}}stuff in the current context{{/fill-outlet}}

were I to use the above implementation, I would do something like this in my component's template:

<button {{action "toggleShowModal"}}>Click Me</button>
{{#if showModal}}
  {{#fill-outlet "modal"}}<div>...my dialogue here</div>{{/fill-outlet}}
{{/if}}
@locks
Copy link
Contributor

locks commented Jan 18, 2015

I really dislike this idea. It breaks the component's isolated nature and can lead to very confusing "bugs" in the application.

@kzgolden-pba
Copy link
Author

I believe the fill-outlet, if it even needs to be a component, would need to break that isolated nature in order for this to work. However, the yielded data inside would be in the correct context. This seems a specific enough case to cover with unit tests such that these bugs you speak of are not a factor.

@lukemelia
Copy link
Member

It would be wonderful to have an elegant solution to modals in Ember. It is one of the more awkward parts of apps I've worked on. This API seems like a pretty good solution to me.

@kzgolden-pba kzgolden-pba changed the title Allow components to insert and remove content with current context into an outlet outside of the component, eg "modal" Handlebars helper or component that yields inside a specified outlet anywhere in the hiearchy Jan 20, 2015
@kzgolden-pba kzgolden-pba changed the title Handlebars helper or component that yields inside a specified outlet anywhere in the hiearchy Handlebars helper or component that yields inside a specified outlet anywhere in the hierarchy Jan 20, 2015
@ef4
Copy link
Contributor

ef4 commented Jan 21, 2015

@lukemelia check out the API for modals in liquid-fire. We could break it out as a separate thing (not dependent on any animation stuff) if there's interest.

http://ef4.github.io/liquid-fire/#/modals

@mitchlloyd
Copy link

I've been pondering the concept of modals lately. @kcgolden or @lukemelia could you tell me why your modals needs to be rendered into a special outlet on the page? I wrote the "cookbook" on this that is in the guides, but now I'm not sure why I opted to render modals into a special outlet. I think I was mislead by the documentation that I read for disconnectOutlet

@kcgolden here is what I propose for your use case. Let me know what you think:

http://emberjs.jsbin.com/cisoko/6/edit

  • I have a dialogue that will manipulate passed in data
  • which I want to make into a component
  • The dialogue would be a triggered by a button
  • which would open the dialogue in a "modal" outlet which lives at the application level
  • I would like the button and dialogue to belong to the same component so everything can be self contained and I don't have to do things like create a special action on the route every time I want to use the dialogue/button combo.
  • This way, I can just insert the component into the template where I want the button to appear, pass in the data and not have to do anything outside of the component.

I think this pattern is more more flexible than what I originally wrote up for the guides:

  1. If you wanted to render different things in a modal you could make the modal-dialog a block component and give it content to render and not even worry about sending in the model.
  2. If you're keen on passing in a model but want a different form inside, you could continue to do so and maybe give it the name of a component to render inside of itself using the component helper.
  3. This pattern allows you to render modals inside of modals

I figure I'm just overlooking something, but I've not been able to think of a good reason that modals need to be rendered into a top level outlet.

If there is a reason that you need your modal in a special outlet then the component & service approach seems like it would work for your use case. That's essentially what @ef4 has implemented in Liquid Fire.

@kzgolden-pba
Copy link
Author

@mitchlloyd - I think the main reason my team puts modals into a single outlet at the application level is so modals of a similar priority level can overwrite each other. A user workflow dialogue only displays one at a time, error modals render above that, but only display one at a time as opposed to stacking the modals. We don't stack them in any way.

@mitchlloyd
Copy link

@kcgolden I can see how that "overwriting" behavior could be useful for certain use cases. Thanks for the follow up!

@davewasmer
Copy link
Contributor

@mitchlloyd another potential shortcoming of your jsbin's approach, unless I'm missing something (quite possible), is z-index conflicts. If the containing element of the {{modal-dialog}} component is deeply nested, other elements could appear above that modal overlay in the paint order. AFAIK, the only way to ensure a modal overlay appears over everything is to have it be a top-level element (just below <body>) and have a high enough z-index.

@mitchlloyd
Copy link

@davewasmer I've never heard of anything quite like the z-index conflicts you're talking about, but I've definitely been surprised by CSS more than a few times :)

My current understanding is that using position: fixed would put things in a new context that sits over other elements that aren't fixed. Also I believe z-index should continue to work no matter how deeply nested something is. One other thing, I'm usually seeing people put their modal outlet / component right above the </body> ending tag.

It might take some JSBin effort to really put this to the test, but one interesting data point is that Boostrap renders their modals right in-line from where they are launched: http://getbootstrap.com/javascript/#modals. It is interesting however that they also first put a 'backdrop' right before the </body> tag. Not sure why that doesn't just go on the modal element.

@davewasmer
Copy link
Contributor

@mitchlloyd I think you are correct that fixed position elements appear over others, but modal overlays aren't always the only fixed elements on the screen.

Here's a JSBin to demonstrate what I mean. It seems that CSS takes a "breadth-first" approach (for lack of a better term) to stacking, but only for elements that "qualify", i.e. position != static and z-index is defined.

In that layout, the only way to guarantee that the .modal-overlay appears over top of everything else is have it be a direct descendent of <body>.

@mitchlloyd
Copy link

@davewasmer Wow, thanks for that great JSBin! That CSS looks like a totally valid use case.

I went to see how Bootstrap handled this with their modals and I can reproduce the same issue that you're showing in your JSBin.

screen shot 2015-04-02 at 4 31 00 pm

Thanks for taking the time to put that together. I learned something here!

@lukemelia
Copy link
Member

We have released a solution to this problem in for ember 1.10 and higher. https://github.com/yapplabs/ember-modal-dialog/ The README has more details.

@tim-evans
Copy link

I'm calling this feature 'wormholes' after yapp-labs :P, and am using it for https://github.com/paddle8/ember-document-title

@kzgolden-pba
Copy link
Author

closing in favor of @lukemelia's comment. Thanks.

kategengler pushed a commit that referenced this issue Jan 19, 2019
Add support for app.import(…, {outputFile: …})
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