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
Modal #3
Comments
Some notes:
|
@wesleycho are you working / planning to work actively on this one? I've started to look into what is possible so can either take it over or bounce off ideas. |
No one is really having anything assigned. Except the stuff we already have as PR, so feel free on bounce ideas. At the end you are the one who knows more :P |
@Foxandxss this is very dangerous assumption, don't make this mistake :-) |
No, we are counting on that, don't let us down. |
I've done looking into this before, but there is an unfortunate thing here - the DynamicComponentLoader kind of sucks to use. It feels like it's underpowered. We should perhaps talk about what we need the modal to do. The modal needs to ultimately slot the modal dialog into a container of a user's choice. Angular Material just decided to go the single insertion way (which may be best initially) by forcing the user to use a container element in the template, and then used a service to insert it into the container while storing a ref to the backdrop and modal in the service after inserting via DCL. On destruction, it then gets cleaned up. I'm not the biggest fan of putting a container right in the template, but it seems to be necessary due to how the DCL works. The DCL seems necessary for this sort of problem, unless we want to go the declarative route and force the user to declare their modal right in the template. I personally prefer imperative declaration of components such as modals through the usage of a service, but the framework seems to make declarative usages easier. However, if we go the declarative route, we then also run into the same problem as alerts with self destruction & reseting of state. |
@wesleycho I hear what you are saying. I'm playing with something right now that might work for the "service" usage without too much pain for the end users. Will shore tomorrow or day after tomorrow. But yeh, DCL needs more love, Misko was showing me some ideas for future evolution. Wish try to push this thing forward. |
@wesleycho this is what I've got so far: http://plnkr.co/edit/877XVmEU05icATk3X7ZK?p=preview Here is the general idea:
Obviously all this requires (much) more work to be usable, I've left some TODOs. There are some open questions as well:
Anyway, here is a starting point, let me know what you think. |
I don't dislike the given solution (I have to check it better, but I have a good first impression). About your questions:
I vote to wait. I keep hearing that it is coming and we are actually working on the docs right now, so probably May is a good date for a first version on animations.
I would prefer not to. People tend to overuse the modals and that only bring pain. Who needs stacked modals anyway? |
@Foxandxss thnx, I've got exactly the same thoughts regarding animations and stacked modals |
Blocked on angular/angular#9293 and angular/angular#8617 |
@pkozlowski-opensource is it still blocked? In this thread you say (9th of June) that there are no more blockers... |
Here is the status update for anyone tracking this issue:
Here is the remaining work if anyone wants to track progress:
The other good news is that API surface can be much smaller in Angular 2 as we don't need @Component({
selector: 'ngbd-modal-basic',
template: `
<template #content let-c="close" let-d="dismiss">
<div class="modal-header">
<button type="button" class="close" aria-label="Close" (click)="d('Cross click')">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title">Modal title</h4>
</div>
<div class="modal-body">
<p>One fine body…</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" (click)="c('Close click')">Close</button>
</div>
</template>
<button class="btn btn-lg btn-outline-primary" (click)="open(content)">Launch demo modal</button>
`
})
export class NgbdModalBasic {
constructor(private modalService: NgbModal) {}
open(content) {
this.modalService.open(content);
}
} |
Note to self - go over some of the modal impl recommendations, ex.: |
Could you please explain why resolve is not needed anymore? Suppose I want to create a reusable confirmation dialog. I would like to have a confirmationService allowing, from any component, to do for example
How would I avoid repeating the whole modal template in every component needing that. It seems that if you pass a string and not a TemplateRef, the string is displayed as is, i.e. not compiled. This was trivial to do in ui-bootstrap, because a controller name and a resolve could be passed as argument. And the controller received a reference to the modal instance and the resolved values. But I don't see (probably due to my lack of Angular 2 experience) how to do the same here. |
This is the case since in the proposed API you can only open modals with strings / TemplateRef. In Angular2 you can't have a template that is a free-flying string - it needs to be embedded in another template by using a
Probably by creating a dedicated component. But to be frank I didn't spend much time looking into extensibility scenarios yet - this discussion is a good occasion to do so.
Exact. We don't want to "compile" this string since it would require shipping a compiler to a browser and would kill most benefits of the offline compilation. TBH the "string" argument is pretty much useless for anything other than testing.
I think that the larger issue is: where would you have a "template" for the common part? Once again, a "free-flying" string won't work in ng2. So we need to think more about this. One approach to explore would be to allow passing component types as argument to the Let's explore things some more but I would like to land the initial version first before spending too much time on extensibility. The good news is that we can always add API - getting taking things out is harder :-) Thnx for sharing this use-case - this is an important point in the discussion! |
We need a way to bind data to our dynamically inserted components I think - is there a mechanism for doing so with ng2 currently? |
I wonder if angular team is aware of this..? |
@pkozlowski-opensource is on the Angular team :) |
:) ok |
I think I would be perfectly fine with a solution where I would do the asynchronous stuff by myself and pass a component type and a map of inputs. This is the kind of stuff I had in mind. In addition to the data, I think it's important to be able to pass the NgbModalRef to the component, because the component itself must be able to close or dismiss the modal when it needs to. |
With this current proposal, it would be possible (but unideal) to do any resolve type behavior by fetching the desired data beforehand in the service wrapper, then store the data on the service, then open the modal which uses a component which also injects the service in order to fetch the data. Not great, but it would be possible with the current proposal. |
Yeh, let's say this is the best proposal we've got for now. But maybe someone can / will come up with alternatives. In addition to the data, I think it's important to be able to pass the NgbModalRef to the component, because the component itself must be able to close or dismiss the modal when it needs to. @jnizet |
@wesleycho Yes, that's approximately what I tried, and I managed to do what I wanted. The only remaining annoyances are that I still need to have this in my enclosing component template:
and that I need to pass this template ref when deleting:
Not a big deal, and the stateful service not ideal either, but it works. |
@pkozlowski-opensource regarding the NgbModalRef, sure it can be passed around, but since it's what is returned by |
In case anyone is interested, I managed to create a reusable confirmation service allowing to display, from anywhere, a customizable confirmation dialog, based on the current WIP by @pkozlowski-opensource, and using the idea suggested above by @wesleycho. Here's a gist containing the code. |
Can't wait this to get release, so I can get rid of angular1 on our project. |
Yeah, me too. The whole Bootstrap 3 or 4 would be a game changer when it works on angular 2! |
Have you thought about an API where you don't use any services? It would look like this <modal
#myModal
[opened]="modalState$ | async"
(close)="handleClose($event)">
<p>some content</p>
<button (click)="myModal.close()">close</button>
</modal> I think this would be a perfect, stateless component. The only problem is, that you'd need a way to somehow render it at the root component instead of the one you actually put it in, and I'm not aware of a way to do it at the moment. I have opened an issue about it angular/angular#11020 |
Yes, but it is not flexible enough for all use-cases. Ex.: opening a modal window with login prompt from an auth service. |
@pkozlowski-opensource ok, there might be use cases where it would not be amazing, even though one could argue, especially when using something like @ngrx/store or redux(and we all know it's gonna be all the rage) you could have that modal permanently sitting in the root component with <modal [opened]="!(isAuthenticated$ | async)">
<login-form></login-form>
</modal> but I feel that in 95% of other use cases, this way would be far more clear and intuitive than using services, promises and other stuff. Wouldn't it at least make a sense to be able to use it both ways? |
Modals are not something that generally make sense to make declarative - in fact, such attempts generally feels like anti-patterns, since almost all use cases don't fit abstracting it away into components as the main controller of behavior when its state lies above the rest of the UI, as well as creating a dependency on component tree structure unnecessarily when it doesn't fit into that hierarchy at a more DOM oriented perspective. I'm against componentizing such in an open source library like this as poor API design/bloat, as well as confusing usage due to promoting multiple patterns instead of promoting a solid powerful & extensible use. We already know from UI Bootstrap and countless other UI libraries that promoting multiple patterns for accomplishing the same goal quickly leads to user confusion, which puts pressure on maintainers having to explain to users nuanced views instead of an answer that is straightforward & easily searchable, especially when one approach is fundamentally more sound than another - that is usually a prime indicator of design problems, and it bleeds over to more complex internal code. Users are free to build abstractions on top of our components to suit their uses, including building component-based modals on top of the library's modal - it makes far less sense to have it at the library level though, since open source libraries should aim to be as extensible & as lightweight as possible. |
Not sure if I understood this correctly, but this is not necessarily true. I'm speaking from a redux-and-the-likes perspective. State of most of my modals would be defined on the slice of state the component belongs to. eg. client add modal, would be inside my clients route component, with state defined in the and when there is a modal that doesn't belong to any particular component, I would put it in the root component. I don't want to abandon the concept of inputs/outputs, reactive dumb/smart components and go back to promises, ugh. And wouldn't it be more align the html5 dialog element as well? https://developer.mozilla.org/en/docs/Web/HTML/Element/dialog
Yes, this is true and it's the only thing bothering me and preventing me from creating the component myself, as positioning of any parent component could screw up positioning of the modal, ideally I'd want the component to be created(or moved to) on the root component(perhaps using some sort of structural directive(?) or maybe something in the decorator, since angular might need to know about it during compilation(??)), and I have opened an issue requesting a feature that would allow it angular/angular#11020
I get it, I just hoped you guys would have idea how do the "put component somewhere but render it on the root instead", since you were considering this approach. |
👍 |
Try this css to make stacked modals work:
Working for me using version 1.0.0-alpha.5 ! |
…own-fixes to master # By jenmak # Via jenmak * commit '8712458fa9840b5fe9b495f98ca5c73c71852610': Replaces s-dropdown-menu with s-typeahead class
Recreate BS4 modal with ng2 component.
The text was updated successfully, but these errors were encountered: