ember default route when url has non-existing route specified [duplicate] - ember.js

How can I handle the error
Uncaught Error: No route matched the URL '...'
and show a custom 404 page?
Note: This question was asked before and answered several months ago - but does not work anymore.

App.Router.map(function() {
//set up all of your known routes, and then...
this.route("fourOhFour", { path: "*path"});
});
.. where you have your FourOhFourRoute defined to show the "no route found" message of your choosing. You will be able to access the originally requested path in the fourOhFour route as the path parameter.
EDIT: just for clarity -- this answer came after the others were reported not to work anymore.
EDIT 2: I've updated the answer to reflect Yehuda Katz's comment (if I have it wrong, please LMK).

Here is an example:
I define the last route in my router using a wildcard route see: http://emberjs.com/guides/routing/defining-your-routes/#toc_wildcard-globbing-routes
I have a /not-found route, see last route defined in my router /*path to catch any text string, see: https://github.com/pixelhandler/blog/blob/master/client/app/router.js#L19
Router.map(function () {
this.route('about');
this.resource('posts', function () {
this.resource('post', { path: ':post_slug' });
});
this.resource('admin', function () {
this.route('create');
this.route('edit', { path: ':edit_id' });
});
this.route('not-found', { path: '/*path' });
});
That route does a redirect to /not-found, see: https://github.com/pixelhandler/blog/blob/master/client/app/routes/not-found.js
import Ember from 'ember';
export default Ember.Route.extend({
redirect: function () {
var url = this.router.location.formatURL('/not-found');
if (window.location.pathname !== url) {
this.transitionTo('/not-found');
}
}
});
Also any route having a hook (e.g. model, beforeModel, afterModel) that results in a rejected promise, can use the error action to transition to the 404.
actions: {
error: function (error) {
Ember.Logger.error(error);
this.transitionTo('/not-found');
}
}
Which renders a not-found template, see: https://github.com/pixelhandler/blog/blob/master/client/app/templates/not-found.hbs
<h1>404 Not Found</h1>
<p>
Perhaps you have a link that has changed, see {{#link-to 'posts'}}Archives{{/link-to}}.
</p>
Here is my 404 page: http://pixelhandler.com/not-found

You could try adding a catch-all route at the end of your router:
App.Router.map(function() {
this.resource('post', ...);
this.resource('user', ...);
this.route('catchAll', { path: '/*' });
});
App.CatchAllRoute = ...

In Ember 2.x
Inside the App.Router.map function, put code below the the end of the callback function.
this.route('your_handler_route_name', { path: '/*path' });
Now every route does NOT catche by the previous defined routes will be catched by your_handler_route_name route.

Solution 1
To display 404 content:
App.Router.reopen({
handleURL: function (url) {
try {
return this._super(url);
} catch (error) {
if (error.message.match(/No route matched the URL/)) {
return this._super('/404');
}
}
}
});
If you want to URL changes to 404 as well:
App.Router.reopen({
location: locationImplementation,
handleURL: function (url) {
try {
return this._super(url);
} catch (error) {
if (error.message.match(/No route matched the URL/)) {
this.transitionTo('404');
return this._super('/404');
}
}
}
});
To understand what happened here see line 22636 in ember rc2.
Solution 2
Parse current URL and check if route or resource exist using App.Router.router.recognizer.hasRoute('route.path.goes.here');

Related

What is the difference between route and path in EmberJs

What is the difference between route and path in EmberJs
Router.map(function () {
this.route('about');
this.route('contact', { path: '/getting-in-touch' });
});
The first argument to route is the name of the route. It's used to find the right files to load app/routes/about.js and to provide links <LinkTo #route="about">About</LinkTo>. If you provide a path option it is used to create the URL you see in the location bar for the browser.
From the ember guides
You can leave off the path if it is the same as the route name.
For your case the following are equivalent:
Router.map(function () {
this.route('about', { path: '/about' });
this.route('contact', { path: '/getting-in-touch' });
});
Router.map(function () {
this.route('about');
this.route('contact', { path: '/getting-in-touch' });
});
Will results in Ember knowing how to load URLs for https://yoursite.com/about and https://yoursite.com/getting-in-touch
And for <LinkTo #route="contact">Contact Us</LinkTo> to create a link with HTML like Contact Us

Arbitrary depth slash-delimited param value in Ember route

I have a route defined as:
Router.map(function() {
this.route('folder', { path: '/f/:path' }, function() {} );
});
And the route itself as:
export default Ember.Route.extend({
model(params) {
const path = params.path;
console.log(`path=${ path }`);
return path;
}
});
Currently:
http://localhost:4200/f/folder
works but
http://localhost:4200/f/folder/subfolder
throws a Uncaught UnrecognizedURLError {message: "/f/folder/subfolder", name: "UnrecognizedURLError"} since the router is expecting me to define a route at each level.
Use case is the ability for users to build an arbitrary tree of folders. Is there a way to do this?
I should have read one more paragraph here: https://guides.emberjs.com/v2.6.0/routing/defining-your-routes/
What I'm looking for is a wildcard / globbing route.
Router.map(function() {
this.route('folder', { path: '/f/*path' });
});
Gives me the output I was hoping for:
path=folder/subfolder

Ember route not found

i try to build an webapp with emberjs. this is the app router:
App.Router.map(function() {
this.route("page");
this.route("menu");
this.resource('posts', function(){
this.resource('post', { path: '/:post_id' });
});
this.route("index", { path: "/" });
this.route("cat");
this.route("foto");
});
and this is the Postroute:
// GET POST JSON
App.PostRoute = Ember.Route.extend({
model: function(params) {
return Ember.$.getJSON('http://www.wilhelminaschool.eu/?json=get_post&post_id='+params.post_id);
}
});
but i get an route not found error for the post, the posts list works. What i am doing wrong?
error:
Error: Assertion Failed: The route post/11330 was not found
live on:
http://www.wilhelminaschool.eu/app2/#posts
http://www.wilhelminaschool.eu/app2/#post/11330
Each one of the posts links to app2/#post/:post_id i.e. app2/#post/11330 , but since the post resource has been defined within the resource of posts with a path of /:post_id the links should be app2/#/posts/:post_id i.e. app2/#/posts/11330
example,
http://emberjs.jsbin.com/budeyaja/1/edit
http://emberjs.jsbin.com/budeyaja/1 (please observe the urls while navigating)
If you need the links to work as they are then the routes will have to be specified as ,
this.resource("posts");
this.resource("post", {path:"/post/:post_id"});
http://emberjs.jsbin.com/qaquzusi/1/edit
Do not nest the post resource inside posts, use:
this.resource('posts');
this.resource('post', { path: '/post/:post_id' });
Ember Routing Guide provides a clear explanation of different cases.

Catch-all route is getting priority over star route in ember

I have a route that catches all missing routes and renders a 404-style page. I would like to create a route that matches any url starts with "/browse/" such as "/browse/shoes/red". This seems like the correct way to do that:
App.Router.map(function() {
this.route('browse', { path: '/browse/*fields' });
this.route('missing', { path: '/*badPath' });
});
However, ember's RouteRecognizer always picks the missing route over the browse route. (The logic that does this is in sortSolutions of route-recognizer.js .) Is this a bug in Ember? Is there a right way to use glob routes and still have a 404 handler?
By the way, I can create a resource for browse instead of making it a route like this:
App.Router.map(function() {
this.resource('browse', { path: '/browse' }, function() {
this.route('baz', {path: '/*'});
});
this.route('missing', { path: '*' });
});
This still has the same problem.
I think this must be a bug...
Here's a JSBin : http://jsbin.com/ucanam/1403/edit
Here you can see it going directly to the 'missing' route as expected:
http://jsbin.com/ucanam/1403#/some/random/stuff
And a failed attempt at going directly to a 'browse' route :
http://jsbin.com/ucanam/1403#/browse/test/stuff

Ember Router - How to handle 404 (Not Found) routes?

I'm trying to figure out how to handle invalid routes within my application using Ember.Router.
Currently if I enter an invalid route, e.g. myapp.com/#FooBarDoesntExist, it will redirect to the index route ('/'). I'd like it if I could define a notFound or 404 state that it would route to so I can inform the user what happend. As opposed to them getting dumped on the home page.
A good way to handle this problem is to declare a route who map all possible urls in addition to your routes. You can an example here : http://jsfiddle.net/mbreton/r3C9c/
var App = Ember.Application.create();
App.Router.map(function(){
this.route('detail', {path: "detail"});
this.route('missing', { path: "/*path" });
});
App.MissingRoute = Em.Route.extend({
redirect: function () {
Em.debug('404 :: redirection to index');
this.transitionTo("index");
}
});
App.ApplicationView = Em.View.extend({
didInsertElement:function(){
$('#missingLink').on('click', function (e){
window.location.hash = "#/pepepepepep";
return false;
});
}
});
In this example all unknown urls are redirect to index route.
Ember.Router in its current version does not provide means to handle unknown routes. Time to hack!
Solution 1 - Quick and dirty
The idea here is the following. We have the Ember.Router.route(path) method, which is invoked with the requested (potentially unknown) path. After the invocation of this method, the path of the router is guaranteed to be known. So, if we compare the requested path and the actual path and they differ - then the requested path is invalid and we may redirect a user to the 404 page.
App.Router = Ember.Router.extend({
route: function(path) {
this._super(path);
var actualPath = this.get("currentState").absoluteRoute(this);
if (path !== actualPath) {
this.transitionTo("404page");
}
}
});
This solution is quite expensive. For example, if the current state is "/a/b/c", and a user wants to navigate to "/b/d/e/unknown", the router will dutifully enter known states "b", "d" and "e", and only then we discard the path as unknown. It would be nice if we can tell this before the actual routing starts.
Solution 2 - Fiddling with private methods
Here we check the validity of the given path, and only then tell the router to proceed:
App.Router = Ember.Router.extend({
checkPath: function (path) {
path = path.replace(this.get('rootURL'), '').replace(/^(?=[^\/])/, "/");
var resolvedStates = this.get("states.root").resolvePath(this, path);
var lastState = resolvedStates.get("lastObject");
return lastState.match.remaining == "";
},
route: function(path) {
if (this.checkPath(path)) {
this._super(path);
} else {
this.transitionTo("404page");
}
}
});
This solution also has its drawback - it uses the resolvePath method which is marked as private. Nevertheless, I'd use this solution, since it is more effective than the first one.
The recommended way to do this in Ember 1.13 is to create a catch-all route:
Router.map(function () {
this.route('home');
this.route('login');
this.route('404', { path: '/*path' }); // capture route in path
});
Then put your 404 template in 404.hbs.