Skip to content

Requests

If you prefer to navigate using Javascript, or need more functionality than what UJS offers, Superglue comes with two functions built around fetch, visit and remote. These are wrapped with your own implementation in application_visit.js and can be accessed via the NavigationContext.

Tip

Superglue does not come with a <Link> component. Instead we encourage you to build one that is unique to your projects needs using the functions provided by the NavigationContext.

import { NavigationContext } from '@thoughtbot/superglue';

const { remote, visit } = useContext(NavigationContext)

visit

visit is designed to mimic browser navigation for clicks and form submissions without the impact of a full page reload. There can be only one visit at a time and when successful visit will swap out the current page component for the next one.

At glance it looks like this:

sequenceDiagram
    autonumber
    Browser ->> Superglue: Click request to `/posts/new` intercepted
    activate Superglue
    Superglue -->> Server: Re-request with format JSON `/posts/new.json`
    activate Server
    Server -->> Superglue: `/posts/new.json` response
    Superglue -->> Superglue: Save response and swap page components
    deactivate Server
    Superglue -->> Browser: Update browser history, scroll position
    deactivate Superglue

Hint

Its possible to modify the visit payload before it saves to the store. See the beforeSave callback.

remote

Use remote when you want to asynchronously update parts of a page or save a page to the store without swapping the page component or change the browser history. Unlike visit, you can fire off as many async remote requests as you want.

Hint

Its possible to modify the remote payload before it saves to the store. See the beforeSave callback.

At glance it looks like this:

sequenceDiagram
  alt target default current page
    autonumber
    Browser ->> Superglue: Click request to `/posts/new` intercepted
    activate Superglue
    Superglue -->> Server: Re-request with format JSON `/posts/new.json`
    activate Server
    Server -->> Superglue: `/posts/new.json` response
    Superglue -->> Superglue: Save response
    Superglue -->> Browser: User on current page sees update
    deactivate Server
    deactivate Superglue
  end

By default, remote derives a pagekey from the response to save the page. You can override this behavior and expliclity pass a pageKey option to target a different page in the store. If the user is not viewing the target page, they will not see an update.

Warning

The componentIdentifier from the page response MUST match the target page, otherwise remote will throw a MismatchedComponentError error. You can override this by using the force: true option. See the docs for details.

sequenceDiagram
  alt target another page in the store
    autonumber
    Browser ->> Superglue: Click request to `/posts/new` intercepted
    activate Superglue
    Superglue -->> Server: Re-request with format JSON `/posts/new.json`
    activate Server
    Server -->> Superglue: `/posts/new.json` response
    Superglue -->> Superglue: Save response or update target page
    Note right of Browser: User does not see an update to the current page
    deactivate Server
    deactivate Superglue
  end
  • See note for differences between remote and data-sg-remote

Customizations

You can modify the behavior of visit and remote functions globally from application_visit.js. If you need a global customization, e.g, progress bars, you can add them there.

The beforeSave callback

Note

beforeSave is an advanced Supeglue feature. Before proceeding please familiarize yourself with:

  1. Knowing how Fragments and FragmentRefs work, the first parameter passed to beforeSave is a proxy that lazily normalizes fragments.
  2. How to get the unproxied state.
  3. Knowing the shape of savePage or graft responses.
  4. Knowing how denormaliztion works

Both visit and remote can be passed a beforeSave callback. This is your opportunity to modify the incoming savePage or graft payload before it persists. Its ideal for features like infinite-scroll where you need to concatenate a list of results into an existing list:

const beforeSave = (prevPageProxy, receivedResponse) => {
  receivedResponse.data.messages = [
    prevPageProxy.data.messages,
    ... receivedResponse.data.messages
  ]

  return receivedResponse 
}

remote("/posts", {beforeSave})

Warning

If you are concatenating arrays in a beforeSave callback and using nesting Fragments like so:

index.json.props

  json.posts(partial: ["post_list", fragment: "posts_list"]) do
  end

_post_list.json.props

  json.array!(partial: ["post", fragment: ->(post){"post-#{post.id}" }]) do
  end

_post.json.props

  json.title post.id
  json.body post.body

be sure to use the key to help Superglue identify fragments in the concatenated array.

_post_list.json.props

- json.array!(partial: ["post", fragment: ->(post){"post-#{post.id}" }]) do
+ json.array!(partial: ["post", fragment: ->(post){"post-#{post.id}" }, key: :id]) do
  end

This will ensure that Superglue denormalizes the fragments properly.