Modals
Modals are easy. Lets imagine a scenario where we have two urls:
/posts
/posts/new
When a user visits /posts/new
from /posts
, we want a modal to appear overlaying the existing list of posts. The overlay should work if a user chooses instead to directly visit /posts/new
.
The setup
Both urls render a list of posts. Lets set up the controller and the page_to_page_mapping.js
the same way.
=== "posts_controller.rb
" !!! info "Same template different action" Notice that we're rendering the index
for the new
action. While the content is the same, the componentIdentifier
is different as that has been setup to use the controller and action name.
=== "page_to_page_mapping.js
" !!! info Similarly, we tie the componentIdentifier
to the same page component.
Add a link to /posts/new
/posts/new
Imagine a list of posts, lets add a button somewhere on the index page to direct the user to /posts/new
. As seen previously, both /posts
and /posts/new
render the same thing.
=== "posts/index.json.props
" ```ruby # app/views/posts/index.json.props
=== "posts/index.js
" ```js import { useContent } from '@thoughtbot/superglue'
The modal
The link appears and we're able to navigate to /posts/new
, but /posts/new
is missing a modal. Not surprising as both routes are rendering the same content.
Lets add a modal.
=== "posts/index.json.props
" !!! info For simplicity, we'll use a "Hello World" as the modal contents ```diff # app/views/posts/index.json
=== "index.js
" ```diff + import Modal from './Modal'
=== "Modal.js
"
Too many modals
Unfortunately, now BOTH routes have modals! Lets fix that by adding a conditional render.
=== "index.json.props
" ```diff # app/views/posts/index.json.props
=== "posts_controller.rb
" ```diff # app/controllers/posts_controller.rb
=== "Modal.js
" ```diff import Modal from './Modal'
Finish!
Awesome! We have modals! Unfortunately, clicking <a href={newPostPath}>New Post</a>
will cause a new page load. We can remove the page load by adding data-sg-visit
to the link. With data-sg-visit
, Superglue will navigate to the next page without reloading the page, just like Turbo.
posts/index.js
posts/index.js
Optimization
With the above, a click on New Post while on /posts
will
Fetch
/posts/new
withformat=json
Save the page to the store
Swap the page components
Change the url
Unfortunately, step 1 is still a full page load. Commonly, we just want to load the modal without loading the entire page.
Lets fix that!
index.json
index.json
Recall how digging for content works. We'll add a props_at
that digs for the modal on /posts/new
while skipping other content on that page.
With that change, the sequence becomes:
Copy the state in
/posts
to/posts/new
in the store.Fetch
/posts/new?props_at=data.createPostModal
Graft the result to the store at
/posts/new
Swap the page components
Change the url
Last updated
Was this helpful?