Navigate to non-existent pages

Weā€™re trying to allow users to navigate between pages within a form but are running into a few issues, the URL structure is something like:

  • /contact/
  • /contact/page2/
  • /contact/page3/

(This is an example, the form in question isnā€™t a contact form :smile:)

Within WP the initial /contact/ page has been created but these ā€œsub-pagesā€ havenā€™t. Iā€™ve created a handler which will load the page data from the initial /contact/ page, accessing these pages directly works fine but when a user clicks back/forward in their browser weā€™re noticing within our Theme component, the router link is ā€œundefined/ā€ and as such returns no data required for the page e.g. Yoast, ACF, etc.

Currently when a user navigates to the next page of the form weā€™re using history.pushState:

let slug = "page2"; // Slug is created based off the current page the user is viewing
window.history.pushState({ data: [..] }, 'Page Title', `/contact/${slug}/`);

Weā€™ve toyed around with both popstate and beforeunload window events to try and capture this but they seem to either get called too late (if at all) within these events weā€™ve tried manually setting the router:

actions.router.set("/contact/page2/");

But still have the same issue. Iā€™m probably missing something super obvious here, but Iā€™m not really sure whatā€¦

Ideally weā€™d like to just re-render the form with the new page instead of loading an entirely new page.

One question: Why do you need to change the URL of the form?

Iā€™ve never had to deal with handling back/forward browser actions before so figured pushing these pages into the history would have been an easier way to manage moving between pages & refreshing pages so the user will land back on that page.

Iā€™m open to suggestions, nothing is set in stone.

Hi @chris! :wave:

Itā€™s hard to diagnose this without knowing more details :slightly_smiling_face:

If you are using actions.router.set("/contact/page2/"); then the link should definitely not be undefined anymore!

Would you be able to provide a codesandbox example based a link to a site with the problem that you described or a short video illustrating the problem?

Could you post the code from your form component where you use your form?

Is there any error in the console in when the user navigates backwards/forwards?

@chris

Could you also try to add a breakpoint on the popstate browser event and see if by any chance the state.link inside of that event is null or undefined when you try to navigate back / forth?

@chris I guess what you want is all those Frontity URLs (/contact/, /contact/page2/ and /contact/page2/) pointing to the same WordPress URL: /contact, right?

Thatā€™s not something that can be done in the current version of source but we are working on a new version where that configuration will be possible.

Since we get to that point, my recommendation is to stick to a single URL and save the progress of your form in the client using localStorage, including the subpage the users are currently in. That way, if the user refreshes the page, it will be in the same place where they left off.

You can use a React hook that works similar to useState but saves the data on localStorage like this one: https://www.npmjs.com/package/use-persisted-state

Remember to include a reset button so users can go back to the subpage 1.

1 Like

Youā€™ve hit the nail on the head, thatā€™s exactly what weā€™re trying to do.

Weā€™re already using sessionStorage to store the data so we can load it when the user refreshes. Weā€™ve already got back/next buttons within the form but a new requirement that has arisen is to tap into the browser actions so when the user hits the back button, theyā€™re brought to the previous page within the form and not the last page they visited.

Hence why I thought the initial theory of pushing items into the history would have been an easier way to manage this.

Fortunately weā€™ve managed to figure out the errors in my previous post, turns out I was trying to access a property within the state object before it had finished fetching - a quick check with isFetching solved it.

Now Iā€™m trying to figure out an issue with the form not re-rendering when properties within the Frontity state are changed - this is almost definitely me doing something dumb rather than an actual Frontity issue though.

1 Like

Another idea that just came to my mind is to bypass the Frontityā€™s routing for those URLs.

const Theme = ({ state }) => {
  // ...
  const isContatPage = state.router.link.startsWith("/contact/");

  return (
    <Switch>
      <ContactPage when={isContactPage} />
      <Loading when={isLoading} />
      {/* ... */}
    </Switch>
  );
}

Then, inside ContactPage, extract the page number from the URL:

const ContactPage = ({ state }) => {
  const page = /\/contact\/page(\d)/.exec(state.router.link)[1];
  // ...
};

If you do that, I think you can use actions.router.set and forth and the browser back/forward button should work.

The problem with that approach is that the SSR of the /contact/page2 URL will return a 404 because it doesnā€™t exist on your WordPress but you can create empty pages that match those URLs.

Can you show us the code? :slight_smile: