ember.js icon indicating copy to clipboard operation
ember.js copied to clipboard

Error when using replaceWith over a catch-all route

Open vmalloc opened this issue 6 years ago • 2 comments

In this scenario, I'm trying to achieve a "404" route to display a proper message. This is done via this pattern in the router:

  this.route("not_found", { path: "/*:unknown" });

So far so good. Then I'd like any route that tries to access a non-existing record (i.e. ajax getting 404 responses) to redirect to the same "not found" route, to achieve a unified UX. The only way I found to do this is by adding the following in the application route's error action handler:

error(err, transition) {
      let router = this.get("router");
      if (err.errors && err.errors[0].status === "404") {
        transition.abort();
        return later(function() {
          let transition_name = transition.to.name;
          let url = router.urlFor(transition_name, transition.to.params);
          return router.replaceWith("not_found", url);
        });
      }
    },

However, this does not always work. Since the transition URL starts with a slash, the error we're getting is pretty weird:

history_location.js:223 Uncaught DOMException: Failed to execute 'replaceState' on 'History': A history state object with URL 'http://items/2' cannot be created in a document with origin 'http://localhost:4200' and URL 'http://localhost:4200/items/2'.

Fixing it works by adding the following after the call to urlFor:

          if (url.startsWith("/")) {
            url = url.substr(1);
          }

Reproduction repo: https://github.com/vmalloc/ember-bug-18515 (note - the repo is with the workaround)

vmalloc avatar Oct 24 '19 10:10 vmalloc

It may be indeed possible to achieve the same result with a different method - if anyone can point me to that method, I'd be very grateful. This approach also doesn't correctly handle cases where the requested route ends with .index so I'm also looking for ways to improve it.

vmalloc avatar Oct 24 '19 10:10 vmalloc

Instead of a defined route with a glob dynamic segment, you can also do this.intermediateTransitionTo('error'). This has the effect of going to your error route, but not updating the URL, which seems to be what you want.

mehulkar avatar Oct 24 '19 17:10 mehulkar