As I work on side projects, I sometimes stumble upon a pattern that I really
like. This is one of those times. Today, I’ll show you how to implement a detailed view of a list item as a modal using a child route.
If you play around with the live demo you'll notice that the URL updates when a rule is clicked on and a modal renders. This means that we can refresh the page and the modal will render with the list of rules in the background. It’s a nice touch because we’ll always be able to see the rule in the context of the game.
The Router
We have a parent route called Game
that has two child routes — Game Rules
and Game Rule
. I’m using a separate route for rules, because eventually I’m going to let user’s create groups of rules called rulesets, and I would like to be able to separate that out as another route, eventually.
Of note, the Game Rules
route renders only one component for the page view (lines 24–26) while the Game Rule
route also renders the RuleSingle
component for the rule view (line 36). This will make sense once you see the GameSingle
component.
Also of note, we’re leveraging router meta which will be used in the GameSingle
component to determine if the modal should be shown. We want it to show for Game Rule
but not for Game Rules
.
The GameSingle Component
I’m excluding all the styling from the following components for brevity’s sake.
This component has two <router-view>
tags, one for the page (line 10), and one for the rule (line 15). Note that the <modal>
component (shown below) will only be shown if showModal
is true. We determine if showModal
is true based on the route meta (line 31). Lastly, we’re going to want to watch the route meta value and update showModal
accordingly (lines 35–39). When a user clicks on a rule, the route changes causing the showModal
value to be true, which in turn renders <modal>
and its children.
The Modal Component
We wrap the entire component in a <transition>
and use custom functions to handle the enter and leave animation. When the modal is rendered it fades in, and when a user clicks the close button, the router goes backwards in history a step causing the modal to fade out.
Conclusion
There are many ways to implement modals. One way I’ve done this in the past is by creating a modal component in the root App component and use Vuex actions to show it and tell it what content to use. It’s always felt a bit cumbersome to me, but its definitely a viable solution. I like this solution because it doesn’t clutter up Vuex state (which seems unnecessary for this type of interaction) and still allows the modal component to be re-usable.
Top comments (1)
Great job Ramsay! I'm trying to adapt your demo to Nuxt.js but I can't get the pages to render. I'm not sure if the problem is the difference in the routing configuration. I don't see any errors... 😕