What's the best solution to handle 404 error from Ember App.
I tried to catch the error like this :
CL.ApplicationRoute = Ember.Route.extend({
actions: {
error: function(error, transition) {
debugger;
if (error && error.status === 400) {
// error substate and parent routes do not handle this error
return this.transitionTo('modelNotFound');
}
// Return true to bubble this event to any parent route.
return true;
},
}
});
But it seems not to work... :(
Have you any solution ?
I found the solution here : http://dinethmendis.com/blog/2013/7/30/handling-unsupported-urls-with-emberjs
I just added
this.route('missing', { path: '/*path' });
in the router map and then define the missing route.
Related
According to this page, you can have an "error" action in the actions hash in the application route which looks something like this:
actions: {
error: function(error, transition) {
if (error && error.status === 400) {
// error substate and parent routes do not handle this error
return this.transitionTo('modelNotFound');
}
// Return true to bubble this event to any parent route.
return true;
}
}
However, when the server returns a 403 (or presumably any other error status) the "error" argument does not have a "status" property. The only way I can get the status is like this:
actions: {
error: function(error, transition) {
var status = error.errors[0].status;
if(status == '403') {
return this.transitionTo('index');
}
// substate implementation when returning `true`
return true;
}
}
Not a big deal, but it seems wrong to do error.errors[0].status. Am I doing something wrong here?
As I understand, ember tries to pass errors in some 'general' format, suitable for all cases. And in some cases backend may respond with more than one error. I think that's the reason why we have an array of errors in error action.
I am trying to catch 404 errors in my ember app, and redirect to /not-found.
I have an errors action on my ApplicationController, and I have an RSVP.on('error') function too but the 404's aren't getting caught. I just get a 404 error thrown to my console from jQuery, but the error is not getting passed to the error handler.
Errors initializer:
import Ember from 'ember';
var initialize = function(container) {
var errorReporting = container.lookup("service:errorReporting");
Ember.RSVP.on('error', function(err) {
Ember.warn("Ember.RSVP error..... Logging error:");
console.log(err);
if (err.name && err.name === 'TransitionAborted') {
Ember.debug("TransitionAborted error. Doesn't look like we should be catching these.");
} else {
container.lookup('route:application').send('error', err);
}
});
window.onerror = function(err) { // window general errors.
Ember.warn("Uncaught error (tripped window.onerror)..... Logging error:");
console.log(err);
errorReporting.report(err);
};
};
export default {
name: 'errors',
initialize: initialize
};
The error action on my applicationRoute is huge (and I can post it), but it doesn't even seem to be getting called.
EDIT 1: Route Code
import Ember from 'ember';
import AuthenticatedRouteMixin from 'simple-auth/mixins/authenticated-route-mixin';
export default Ember.Route.extend(AuthenticatedRouteMixin, {
titleToken: function(model) {
return model.get('name');
},
model: function(params) {
return this.store.find('location', params.location_id);
}
});
EDIT 2: ApplicationRoute / Error handler
error: function(err, transition) {
if (!Ember.isNone(transition)) {
transition.abort();
}
let errorHolder = this._getErrorDataFrom(err);
let errorMessage = this._getErrorMessageFrom(errorHolder);
let isFourOhFour = (typeof(err.status) !== 'undefined' && err.status === 404) || errorHolder.reason === 'not_found';
if (isFourOhFour) {
return this.transitionTo('not-found');
}
let requireAuthentication = (errorHolder.reason === 'not_authenticated');
if (requireAuthentication) {
window.localStorage.setItem('toast-on-reload', errorHolder.message);
return this.session.invalidate();
}
let isValidationError = ( errorHolder.reason === "validation_error" ||
( !Ember.isNone(errorHolder.errors) && !Ember.isNone(errorHolder.message) ) );
if (isValidationError) {
this.toast.error(errorMessage);
return;
}
let verificationRequired = (errorHolder.reason === "verification");
if (verificationRequired) {
this.toast.error(errorMessage);
return this.transitionTo('verification');
}
let invalidRequest = (errorHolder.reason === 'unprocessable_entity');
if (invalidRequest) {
this.toast.error(errorMessage);
return;
}
this.errorReporting.report(errorHolder);
this.toast.error(errorMessage);
return this.transitionTo('error');
}
},
_getErrorDataFrom: function(obj) {
if (!Ember.isNone(obj.responseJSON)) {
return obj.responseJSON;
} else if ( !Ember.isNone(obj.success) || !Ember.isNone(obj.errors)) {
return obj;
} else if (!Ember.isNone(obj.jqXHR) && !Ember.isNone(obj.jqXHR.responseJSON)) {
return obj.jqXHR.responseJSON;
} else {
Ember.warn("No error handler available, using default ( {} ). Error:");
console.log(obj);
return {};
}
},
_getErrorMessageFrom: function(errorHolder) {
if ( typeof(errorHolder.errors) === 'object' && !Ember.isNone(errorHolder.errors.message) ) {
return errorHolder.errors.message;
} else if (!Ember.isNone(errorHolder.errors)) {
return errorHolder.errors;
} else if (!Ember.isNone(errorHolder.message)) {
return errorHolder.message;
} else {
return "Sorry, something went wrong.";
}
}
If you want to use the error event, then place its handler inside an actions hash in the application route.
Alternatively, consider the use of an error route. You can define this in pods/application/error, with templates, routes, and controllers just like any other route. See http://guides.emberjs.com/v1.10.0/routing/loading-and-error-substates/#toc_code-error-code-substates. The error code will be passed to that error route as its model.
Finally, in many cases it's most simple and reliable to catch the error from the find.
model: function(params, transition) {
return this.store.find('location', params.location_id) .
catch(err => this.send('ajaxError', err));
}
Then define the ajaxError action on your application route which does the same kinds of things you are doing in your error hook now. However, this will catch only ajax errors, not other sorts of errors that might occur during transitions, and be swallowed (or in your case reported by Ember.RSVP.on('error').
I am getting the error below when i navigate from my index page to my detail page detail/3.
This works fine when I type detail/3 URL. I am using breeze with ember js
Error: Assertion Failed: You must use Ember.set() to access this property (of [object Object])
App.IndexRoute = Ember.Route.extend({
model: function () {
return EntityQuery.from('Property').using(manager).execute().then(function (data) {
return data.results;
}).fail(queryFailed);
}
});
App.Router.map(function () {
this.route('add');
this.route('detail', {path:'/detail/:detail_id'});
});
App.DetailRoute = Ember.Route.extend({
model: function (params) {
return EntityQuery.from('Property').where("PROPERTY_ID", "==", Number(params.detail_id)).expand('RENTs').using(manager).execute().then(function (data) {
return data.results[0];
}).fail(function (error) {
alert(error);
});
},
serialize: function (model) {
return { detail_id: model.pROPERTY_ID };
}
});
Thanks in advance
Sadly there is no Breeze "model library adapter" for Ember at this time. I hear tell of people who have married Breeze to Ember. You might search for that topic. It's on our wish list but not enough time yet to get it done ourselves.
I'm using Embers findQuery method and wonder how to catch 404 errors when there are no results?
this.store.findQuery('customer', { hasProjects: true, getArchivedProjects: archived }).then(function(customers) {
});
If the query is empty, the code inside this then function doesn't get fired, so I can't even check the type of customers.
Example:
this.store.findQuery('customer', { hasProjects: true, getArchivedProjects: archived }).then(function(customers) {
console.log('foo')
});
If the query returns a 404, console.log doesn't be fired.
The findQuery function returns a promise. You may then provide two functions to the then(), the first being the success path, the second being the failure path... for example:
this.store.findQuery('customer', { hasProjects: true, getArchivedProjects: archived }).then(function(customers) {
console.log('foo')
}, function(error) { /* do something with error */ });
Alternative answer:
Add a error hook to the corresponding route:
App.CustomersIndexRoute = Ember.Route.extend({
actions: {
error: function(reason) {
if (reason.status === 404) {
// do something ...
}
}
}
})
See: http://emberjs.com/guides/routing/asynchronous-routing/#toc_when-promises-reject.
how is possible handle restAdapter errors from store or adapter?
Now I am using this code:
App.ApplicationRoute = Ember.Route.extend({
model: function(){
var self = this;
return this.store.find('item').then(function(data){
return data;
}, function (error){
console.log('error');
return [];
});
},
});
It would be better something more general. Thanks
Until there is some more sophisticated error handling throughout ember data, you could do something like the following to handle network errors in a cross-cutting way:
Extend the RESTAdapter to parse errors from the xhr object
App.ApplicationAdapter = DS.RESTAdapter.extend({
ajaxError: function (jqXHR) {
jqXHR = this._super(jqXHR) || {status : 'unknown'};
var error;
if (jqXHR.status === 404) {
error = 'not_found';
} else if (...) {
...
} else {
error = 'dunno';
}
return error;
}
});
Extend the store to publish error events when bad things happen
App.Store = DS.Store.extend(Ember.Evented, {
recordWasError: function (record, reason) {
this._super.apply(this, arguments);
this.trigger('error', reason);
}
});
Catch the error in your Application Route
App.ApplicationRoute = Ember.Route.extend({
setupController: function () {
this.get('store').on('error', function (error) {
// Do something with the error
console.error(error);
});
},
...
});