angular / router

The Angular 1 Component Router
MIT License
665 stars 135 forks source link

use case: Support modal dialogs with sub states/views #5

Open leifhanack opened 10 years ago

leifhanack commented 10 years ago

Hi there,

will router support handling modal views with subviews? I hope the attached image will clarify it.

router-with-subviews

I want a wizard-like page flow within a modal dialog. This is currently not possible with ngRoute or ui-router. It would be great if modal dialogs like angular material dialog can be used.

Regards, Leif

EisenbergEffect commented 10 years ago

The router doesn't support modals at all just yet. However, we are hoping to add that. If/when we do add modal support, it will have support for child and sibling routers. So, the answer to your question, "Not yet, but hopefully soon."

On Sun, Jul 27, 2014 at 4:12 PM, leifhanack notifications@github.com wrote:

Hi there,

will router support handling modal views with subviews? I hope the attached image will clarify it.

[image: router-with-subviews] https://cloud.githubusercontent.com/assets/128227/3715005/30e8a350-15ca-11e4-98f9-edbd143ef51c.png

I want a wizard-like page flow within a modal dialog. This is currently not possible with ngRoute or ui-router. It would be great if modal dialogs like angular material dialog can be used.

Regards, Leif

— Reply to this email directly or view it on GitHub https://github.com/angular/router/issues/5.

Rob Eisenberg, President - Blue Spire www.durandaljs.com

leifhanack commented 10 years ago

Good to hear that it is already on your radar. Thanks a lot for your quick feedback.
Regards, Leif

EisenbergEffect commented 10 years ago

Thanks for creating the issue. We can use this to track progress. I'd love to hear more about your modal scenarios. For example, does the modal need to be modal only to the parent view? or is it modal to the entire app? Any sore of use case descriptions you can provide are helpful. I haven't looked into the specifics of material just yet, so I wasn't aware they had a dialog behavior. I'll investigate that.

One thing that is trick about this business is that there's the routing part of modals and then there's the view machinery that handles displaying them. So, one thing we would need to do is work out how people can use our router with different modal systems like material or bootstrap. In your experience, is that something ui-router does well, for example? Or is there any other router we can look at for an example of that sort of separation?

On Sun, Jul 27, 2014 at 5:19 PM, leifhanack notifications@github.com wrote:

Good to hear that it is already on your radar. Thanks a lot for your quick feedback.

Regards, Leif

— Reply to this email directly or view it on GitHub https://github.com/angular/router/issues/5#issuecomment-50286129.

Rob Eisenberg, President - Blue Spire www.durandaljs.com

leifhanack commented 10 years ago

I know ngRoute and ui-router. Both do not support that! Integrating different modal systems might be difficult. Maybe it's easier that you define integration points and the other modal systems might adapt? At least for angular material "you" (angular) have both ends in your hands:) But this is just wild guessing and I don't know the internals of the modal systems.

EisenbergEffect commented 10 years ago

I have some ideas about that. My current thought is that the application developer would plug in a simple provider (via di) that the router can talk to. So, when Angular's router needs to display a modal, it can just call the provider and hand it the Component it needs to display. Then it doesn't care how it actually handles the modal behavior. There's a bit more nuance to it than that. But this would allow for the creation of adapters for material, bootstrap, etc and keep the router itself decoupled from those complexities. One thing we'd have to discuss on the Angular team is whether or not we want to supply a default provider out-of-the-box. That's a bit tricky if you don't have control over the css framework or other aspects of the actual app. In the past (for Durandal) I've made the assumption that Bootstrap was present and used that to my advantage, but provided ways to override the behavior. However, I doubt we can do that in this case. Maybe we can just get away with having an example application that shows how to use a bootstrap provider? I'm not sure.

On Sun, Jul 27, 2014 at 5:36 PM, leifhanack notifications@github.com wrote:

I know ngRoute and ui-router. Both do not support that! Integrating different modal systems might be difficult. Maybe it's easier that you define integration points and the other modal systems might adapt? At least for angular material "you" (angular) have both ends in your hands:) But this is just wild guessing and I don't know the internals of the modal systems.

— Reply to this email directly or view it on GitHub https://github.com/angular/router/issues/5#issuecomment-50286612.

Rob Eisenberg, President - Blue Spire www.durandaljs.com

laurelnaiad commented 10 years ago

Innocent question: what are the benefits of a router being at all involved in a modal?

If a modal is truly modal, then it seems out of scope for a router.

If someone is calling a thing that presents as a floating div, but allows interaction "behind" it while that div is presented, then I can imagine the interest in treating it as a substate, but I don't understand the concept of a router dealing with a modal.

I come primarily from a ui-router background, so I'm sure I'm seeing it through that lens. To me, there's the view state, which indeed has a lot of statefulness to it (params and what not), but a modal seems so terminal and outside of routing that it seems to defy being (or needding to be) routed.

What aspects of 2.0 routing might require interaction with modals and vice versa?

UnicodeSnowman commented 10 years ago

@stu-salsbury +1

we currently accomplish this using uiRouter with a named modal view (either at the root level or within a child, depends on the use case) that can potentially have it's own named child views. The OP diagram seems totally do-able with uiRouter, unless I'm misunderstanding the problem. In my experience, a modal has just been a named view styled as a modal.

Narretz commented 10 years ago

the ui-route faq suggests you use only the onEnter function of the router, open the model in this function, and when you close it you call the transition handler yourself: https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions#how-to-open-a-dialogmodal-at-a-certain-state

I think it's not too far fetched that a route can end in a modal. For example, if you have a "new" dialog, it would be reachable under resource/new. The question is how tight the integration between these components should be. A few things I can think of, based on my usage of the bootstrap-ui router (I haven't used ui-router yet): It should be possible to inject certain data from the parent route into the modal. When the modal closes, the parent route receives the result data in a callback.

leifhanack commented 10 years ago

@stu-salsbury it's not always possible to treat a modal as it was designed for:) After some user validation our UI/UX persons responsible come up with sth shown here

screen shot 2014-08-04 at 22 40 39

The modal dialog acts as a "mini-app" inside the SPA with different views, different states, back and forth navigation, aso.

laurelnaiad commented 10 years ago

I suppose the difference between modal and non-modal views becomes blurred. If the diagram above really depicts a directed graph of states from which the user cannot escape, then it is certainly a case where those states and the transitions become important.

Which reminds me: early on in ui-router development there were folks (@jeme IIRC, in particular) who were very focused on the transitions of a state machine in addition to the conditions of a given state (in ui-router terms) and its view relationships.

Having not had time to really investigate the 2.0 router yet, I don't know if this has been considered/designed/implemented, but the management of the state machine in the example above looks like a bigger deal than anything else pictured, and I think it would be great if the 2.0 router either had facilities for state machine definition/management and/or good hooks that enable one to be grafted into the routing definitions.

maxisam commented 9 years ago

First of all, it is totally do-able with ui-router. I have this design on my project already.

Since I have used it, I totally believe it is a must to new router.

I have the same reason with @leifhanack 's statement.

"The modal dialog acts as a "mini-app" inside the SPA with different views, different states, back and forth navigation, aso."

I think It is very useful to use a modal for user to focus on certain thing.

SanderElias commented 9 years ago

I think this is a non-issue. When you need something like this, you are not talking about a modal dialog, or a mini-app. What you need is that some of the routes/states need a way to hide/disable/obscure what is already on screen. This can be done with 1 extra node/element/tag and some CSS. The router does not need any changes for that. I just updated my router test plunk to display a (very crude) sample of this. Just click on the settings.

Edit: some states/routes that don't update the URL might be needed tough!

maxisam commented 9 years ago

Well, in your way, you need to handle stacking modal, style and other features by yourself. Basically you are just trying to build your own modal that can work well with the new router. Not saying it is not a good idea, but it definitely need some work.

SanderElias commented 9 years ago

@maxisam Not really, you can use whatever you are using already, just replace the awkward service that comes with every modal implementation with some logic in the router. It will be easier to deal with. As an example, I just added an bootstrap dialog to my plunk.

maxisam commented 9 years ago

@SanderElias I know to make it looks like it just needs some CSS work. But I guess you don't know there are couple details isn't handle in CSS. Unfortunately, the devil is always in the detail. "The awkward service" actually spent a lot of efforts to handle all requirements.

Here are couple things I can think on top of my head.

  1. Oversize modal scrolling with backdrop issue. (this one is really popular right now)
  2. stacking modal.

Like I said, I think all the problems can be handled with a custom $modal service that works with new router. However, it is probably not an easy decision to ask people who are using UI Router to change if there is no good solution on this.

At least for me, I don't see anything UI Router can't handle so far, although it is not perfect either.

nlwillia commented 9 years ago

I've done a fair bit of work with ui.bootstrap.modal and ui.router in the app I support, and I will definitely be looking for parity with some of those features before I can consider ngNewRouter as an alternative.

I created this plunk to try to achieve the opening request and play around a bit, but I ran into some problems.

That said, it is possible to launch a modal with the new router even in the primitive state that it's in which is encouraging.

Overall, I'm of the opinion that modals are the same as any other view fragment with the exceptions that they don't physically render in a nested location (which requires some creativity to connect the desired scope) and that they are event-exclusive (but not display-exclusive--at least not completely) with the rest of the page. A router should have first-class support for them or at least not prevent extensions that would add such support.

Wish list:

btford commented 9 years ago

Whew, there's been lots of activity here!

I recently added an example showing how to use routing with the new router – https://github.com/angular/router/tree/master/examples/angular-1/confirm-unsaved

If anyone's interested in hacking onto it to try and show these other features/ideas, feel free. :)

I'm going to take a bit to process these comments and respond to questions and make action items out of the useful bits.

Thanks all!

PeterVdBoogaard commented 9 years ago

Use Case: An in-app chat modal to a logged in user. It would need to persist if going to a different view.

I open an entity details view and see the user who last updated it. I request a chat with the user and we have some way to 'lock' our navigation. I the course of our discussion we navigate away from the details view to some other part of the app but the chat modal is untouched.

SanderElias commented 9 years ago

@PeterVdBoogaard, Why can't you just put the chat outside the viewport(s)? It is a separate module that has nothing to do with routing right?

PeterVdBoogaard commented 9 years ago

@SanderElias It's just an example of how i would use a modal window. It's not a question of can but of want.

SanderElias commented 9 years ago

@PeterVdBoogaard, Ok then why would you want such a thing? This is a genuine question, I'm always interested in learning new things. I really don't understand why you would put such a thing inside a routing system!

PeterVdBoogaard commented 9 years ago

@SanderElias I think you misunderstand what i want to be the responsibility of the routing system. Just the modal. The functionality of what is inside the modal is not part of the routing system, only that it is displayed / instantiated and that it sticks around when a user opens another view in the main window. As for why i would put chat inside my app is mainly the signalling 'problem' of WebRTC. The app could be the hub of a mini ecosystem of communication between the users.

Maybe i'm understanding you wrong with what you mean by 'inside a routing system'?

Narretz commented 9 years ago

I am also interested in this. Having a modal that has a route is pretty much the same as having a nested / sibling viewport, but you don't register it declaratively. How is this useful? For example, you have a list of things, and a modal that let's you create a new thing. For convenience, this should be a route. Similarly, I used a modal to display a detail view of a list item. Inside this modal, I had another declarative route (comments for the item).

I wrote a router that basically allows different "types" of routes, additional to declarative views / viewports. When you look at the new router, you'd basically say, hey this route is of type "modal". You'd then register a custom handler, that implements setting up / tearing down the viewport content, but for modals (in my case bootstrap-modals). Depending on the type of modal used, this would be different; so you'd have different plugins for different modals. Lifecycle hooks would stay the same. Inside the modal you would then be able to add normal viewports. Ideally, how the content is set up would be an implementation detail, but all routing functionality would be independent from that. I haven't looked at the code yet to see how this is feasible.

SanderElias commented 9 years ago

@Narretz You can already do this (and almost everything else in this thread) with the current version of the router. A modal is exactly the same as every other route. The only difference is (mainly) cosmetic, and can be taken care of with some CSS, and a couple of lines of code, as I demonstrated in the plunk I linked in above. In my sample the modal is a sibling, but it could also be a child route. The difference, by a child route everything stay's on the background screen, while in the sibling route case, the background gets cleared. That's a matter of preference, and also solvable.

But I'm better with code as with English, so perhaps you can give me an plunk/fiddle/whatever that shows what you want. I will give it a shot an will try to rebuild it using the current router. Perhaps I'm indeed just missing something obvious. (it might be that I need to wait for a few bugs to disappear before everything is indeed fully doable)

Narretz commented 9 years ago

@SanderElias Yes, that is one way to do a modal, but it's not the most clean way. There are several issues. It requires an ng-viewport directive which is filled with either the complete modal or another directive that starts the modal. Further, modal libraries such as angular-ui-bootstrap append the modal at the end of the body. In this case you'd have a basically empty ng-viewport. It's just not very clean. You'll also have more difficulty with regards to accessibility, simply because you have more elements that you may need to hide (because they are essentially empty). There also seems to be a problem with the modal animation, which does not work in your plnkr. The big problem is that there are essentially two types of views: those contained in a viewport in a hierarchical page structure, and those that are not contained, such as modals - but also dropdowns, and all kinds of overlays. It would simply be nice if the router would allow to hook into the view creation process without requiring a viewport.

SanderElias commented 9 years ago

@Narretz. If its outside the viewport, you don't need to use the router at all, right? just use whatever you are using now, and models will works as they did in the past. You don't need anything special from the router in this case. The animation does not work, simply because I din't build that into the sample. Not hard to add, just another few lines off CSS, or make use of the animation hooks in angular itself. I'm waiting for a few bugs to clear, to show how to use 'modals' without 'clearing' the background route. No rocket science there either. The point is, there is no need for special hooks in the componentRouter regarding modals. One can implement them using what is available.

Narretz commented 9 years ago

@SanderElias

If its outside the viewport, you don't need to use the router at all, right?

Maybe we've misunderstood each other. What I am saying is the modal is visible, but its DOM is not living inside an ng-viewport directive. And I want to use router + modal because the modal content should be reachable from a url.

SanderElias commented 9 years ago

@Narretz, You can arrange that from your controller, right? you do indeed need an empty viewport for that, but is that such a big deal? However, to me it's cleaner if your controller has its own subrouter, that takes care of showing the 'modal' view. That view can have it's own controller, and own subrouters (that can house yet another 'modal')

In my opinion, everything that makes an "modal" an "modal" can be put in a simple template directive. then your modal is just another subroute.

 <my-modal> <!-- I take care of the animation and the background graying, with a simple template -->
    <modal-header>some header</modal-header>
    .. and so on...