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¶
Arriving at both urls results in a seeing list of posts. Lets set up the
controller and the page_to_page_mapping.js
the same way.
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.
Add a link to /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.
The modal¶
Now 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.
Info
For simplicity, we'll use a "Hello World" as the modal contents
Too many modals¶
Unfortunately, now BOTH routes have modals! Lets fix that by adding a conditional render.
Finish!¶
Awesome! We have modals! Unfortunately, clicking <a href={newPostPath}>New Post</a>
will cause a new page load. We can move 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
¶
import Modal from './Modal'
export default PostIndex = ({
newPostPath,
createPostModal,
...rest
}) => {
return (
...
<a
href={newPostPath}
+ data-sg-remote
>
New Post
</a>
<Modal {...createPostModal} />
...
)
}
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
¶
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.
# app/views/posts/index.json
...
- json.newPostPath new_post_path
+ json.newPostPath new_post_path(props_at: `data.createPostModal`)
json.createPostModal do
json.greeting "Hello World"
json.showModal @show_modal
end
posts/index.js
¶
Lastly add data-sg-placeholder
to the link.
import Modal from './Modal'
export default PostIndex = ({
newPostPath,
createPostModal,
...rest
}) => {
return (
...
<a
href={newPostPath}
data-sg-visit
+ data-sg-placeholder="/posts"
>
New Post
</a>
<Modal {...createPostModal} />
...
)
}
With the placeholder, 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
Info
Normally, props_at
cannot be used with data-sg-visit
, that's because the state
needs to exist for Superglue to know where to graft. With data-sg-placeholder
, we
take an existing page and copy that over as a placeholder for what doesn't exist yet.