Display global/misc error message to user - ember.js

I'm trying to display error messages for the user in Ember. Is there a way to do this from Logger? I've read about the error substate, but I think that only displays when there's an error in a transition. Is there a way for me to set a property in the ApplicationController to the error message object (and thus display it in a template)? If there's an error in an AJAX call, or a bug, or some other issue, I want the user to be notified that something is awry.
The Coffeescript:
Ember.Logger.error = (message, cause, stack) ->
console.error(message, cause, stack) #show in console
Raygun.send(new Error(message), null, { cause: cause, stack: stack }) #log error on server
# how do I display the error message to user?, THIS DOESN'T WORK b/c "this" is undefined:
#container.lookup('controller:main').set('errorObjetct', message)
I'm using Ember 1.11.1 in ember-cli.
Anyone have any tips on this?
Bryan

Thanks #blessenm for the link. It doesn't precisely apply because in Ember-CLI I don't reference the global application variable, it did remind me that the initialize function passes the "container" object. Thus, I've been able to make it work like this:
Ember.Logger.error = (message, cause, stack) ->
console.error(message, cause, stack) #show in console
Raygun.send(new Error(message), null, { cause: cause, stack: stack }) #log error on server
# SOLUTION:
container.lookup('route:application').set('errorObject', message)
This runs in initializers/error-handling.coffee's initialize function.

Related

What happens when ember's model hook's request fails

I have a typical scenario.
My model hook for Route-1 looks something like this.
model() {
return Ember.RSVP.hash({
posts: this.store.findAll('post'),
authors: this.store.findAll('author')
});
}
If I'm on Route-2 and navigate to Route-1 it will call the model hook.
And if I already have data on my store, both the findAll requests are resolved, triggering RSVP.hash to resolve.
But if the request fails, I'm getting undefined error in my console (chrome).(twice for each of findAll)
My error tracking system reports it as Unhandled promise error detected
the stack shows no relevant info either
defaultDispatch # ember.debug.js:18008
dispatchError # ember.debug.js:17987
onerrorDefault # ember.debug.js:31634
trigger # ember.debug.js:58713
(anonymous) # ember.debug.js:59614
invokeWithOnError # ember.debug.js:346
flush # ember.debug.js:405
flush # ember.debug.js:529
end # ember.debug.js:599
(anonymous) # ember.debug.js:1165
I am not able to figure out what is causing the error to be thrown because the promise findAll already got resolved. And ember tells me I have not handled the promise!
I tried putting catch/reject codes everywher but it never gets called. Because of course the promise was already resolved. So, it can not be rejected.
Then where is this error coming from!! I have no clue. There is no error till the adapter returns.
The only thing I could find was in my serializer normalizeFindAllResponse was not invoked whenever such failures happened.
Any help is greatly appreciated. Thanks!
I somehow solved this issue.
Before, in my adapter I was rejecting the promise with Promis' reason object.
Now, in case of error response, I am rather sending an object containing errors array, rather then failure reason object.
So, the object will get passed as payload to my normalizeFindAllResponse in serializer. There I check for existance of errors array in our payload parameter.
If there is such object then just return an empty object with data attribute set to empty array.
Note: Got the idea from here.

Getting "Error: Assertion Failed: calling set on destroyed object" when trying to rollback a deletion

I am looking into how to show proper deletion error message in ember when there is an error coming back from the server. I looked at this topic and followed its suggestion:
Ember Data delete fails, how to rollback
My code is just like it, I return a 400 and my catch fires and logs, but nothing happens, when I pause it in the debugger though and try to rollback, I get Error: Assertion Failed: calling set on destroyed object
So A) I cannot rollback B) the error is eaten normally.
Here is my code
visitor.destroyRecord().then(function() {
console.log('SUCCESS');
}).catch(function(response) {
console.log('failed to remove', response);
visitor.rollback();
});
In case it's relevant, my model does have multiple relationships. What am I doing wrong? Ember-data version is 1.0.0.8 beta (previous one from the release a few days ago).
Thanks in advance.
EDIT
I discovered now that the record actually is restored currently inside the cache according to ember inspector, but the object will not reappear in the rendering of the visitors. I need some way to force it to reload into the template...
After destroyRecord, the record is gone and the deletion cannot be rolled back. The catch clause will just catch a server error. If you want the record back, and think it's still on the server, you'll have to reload it.
See the following comment on deleteRecord from the Ember Data source:
Marks the record as deleted but does not save it. You must call
`save` afterwards if you want to persist it. You might use this
method if you want to allow the user to still `rollback()` a
delete after it was made.
This implies that a rollback after save is not possible. There is also no sign anywhere I can see in the Ember Data code for somehow reverting a record deletion when the DELETE request fails.
In theory you might be able to muck with the isDeleted flag, or override various internal hooks, but I'd recommend against that unless you really know how things work.
Try reloading the model after the rollback. It will reload from the server but it was the only way around this that I could find.
visitor.destroyRecord().then(function() {
console.log('SUCCESS');
}).catch(function(response) {
console.log('failed to remove', response);
visitor.rollback();
visitor.reload().then(function(vis)
{
console.log('visitor.reload :: ' + JSON.stringify(vis));
});
});
Hope that helps.

Rolling back a deletion to handle a server error in Ember.js

We have an Ember.js application which uses Ember Data. We are trying to do the following:
Delete a record.
If there is a server error (due to the fact that the application can have a "locked" state where records can not be deleted), roll the record back to its previous state, prompt the user to unlock app, and continue.
If there is no server error, continue as normal.
We have found that this does not work
object.destroyRecord().then ->
# handle success
, (reason)->
object.rollback()
# prompt for the unlock
In both cases, we see an error that looks like:
Error: Assertion Failed: calling set on destroyed object
But it isn't clear how to remove the isDestroyed state once it has been set.
In general, it seems that, in either case, once we call destroyRecord, there is no way to rollback the changes to a pre-deleted state once, even if there is a server error.
Try deleteRecord, followed by save. The docs explicitly state that this allows you to rollback on error.
object.deleteRecord()
object.save().then( ->
# handle success
, (reason) ->
object.rollback()
)
I've found that you need to put the rollback call in becameError() function.
// Overwrite default destroyRecord
destroyRecord: function () {
this.deleteRecord();
this.save().then(
function (){
//Success
},
function () {
//Failure
}
);
},
becameError: function (item) {
this.rollback();
}
The item will disappear from views until the server returns the error and then magically reappear.

Ember App Kit: Router#updatePaths throws TypeError

I try to migrate an existing Ember.js project to use Ember App Kit and I'm seeing some strange error which I think should not happen here...
If I start the app, everything is initialized, my util classes are up and running and Ajax requests are sent and received - everything seems well. But then I keep getting the same error over and over again:
Uncaught TypeError: Cannot read property 'name' of undefined
If I follow down the StackTrace I came to see that the error occurs in the updatePaths() function of the Router (I commented on the lines where the code starts to fail:
function updatePaths(router) {
var appController = router.container.lookup('controller:application');
if (!appController) {
// appController might not exist when top-level loading/error
// substates have been entered since ApplicationRoute hasn't
// actually been entered at that point.
return;
}
var infos = router.router.currentHandlerInfos, // <-- empty Array ([])
path = Ember.Router._routePath(infos); // <-- empty String ("")
if (!('currentPath' in appController)) {
defineProperty(appController, 'currentPath');
}
set(appController, 'currentPath', path);
if (!('currentRouteName' in appController)) {
defineProperty(appController, 'currentRouteName');
}
set(appController, 'currentRouteName', infos[infos.length - 1].name); // throws Uncaught TypeError: Cannot read property 'name' of undefined
}
Here is the StackTrace:
Uncaught TypeError: Cannot read property 'name' of undefined ember.js:35015
updatePaths ember.js:35015
Ember.Router.Ember.Object.extend.intermediateTransitionTo ember.js:34522
(anonymous function) ember.js:34919
forEachRouteAbove ember.js:34869
defaultActionHandlers.loading ember.js:34915
triggerEvent ember.js:34983
trigger ember.js:34116
Transition.trigger ember.js:33952
Ember.Router.Ember.Object.extend._fireLoadingEvent ember.js:34750
DeferredActionQueues.flush ember.js:5893
Backburner.end ember.js:5984
Backburner.run ember.js:6023
Ember.run ember.js:6426
runInitialize ember.js:39637
jQuery.Callbacks.fire jquery.js:3063
jQuery.Callbacks.self.fireWith jquery.js:3175
jQuery.extend.ready jquery.js:3381
completed jquery.js:3397
Also, it seems that the appController is not my instance of the ApplicationController but a generated controller from ember itself and I can't see why (my ApplicationController is defined in app/controllers/application.js...
Does anybody know anything about this behaviour or could show me the right direction to track down this error somehow?
So, I digged deeper into this error and also found an issue over at the GitHub project which is describing what I thought was exactly my problem too.
It turns out that somehow Ember App Kit (or even Ember itself) is swallowing messages/errors thrown by Ember.assert and the like so that I followed the suggestion of Stefan Penner and switched to pause on caught exceptions within my browsers dev tools and I saw that it's not one, but several errors!
Unfortunately all these errors fail silently until the last error cannot be caught anymore which is why every error showed the same Stack Trace...
So, the solution seems to be to be sure to pause on caught exceptions and trace down the error message in Ember.assert()... has anybody else seen the same problem and has some other suggestions or could approve my conclusion?
Screenshot of "pause on caught exceptions" in Chrome Dev Tools:

Debugging Ember.js errors: Error while loading route

While in any particular case there are hints and clues on how to debug an error you get, I haven't really found a general Ember strategy.
For example, a typeError while loading a route:
Assertion failed: Error while loading route: TypeError: 'undefined' is not an object (evaluating 'window.router.lander') (ignore the fact that I'm trying to access window.router.lander. It's irrelevant)
Why does Ember not tell you which route it's loading when this error happens? Or whether it happens in afterModel(), or activate()? And what's the general strategy for finding that sort of context info?
So far all I've got is adding a bunch of console.logs scattered around. For example with the error above:
1) Find all occurrences of window.router.lander in my code
2) before the first occurrence, add a console.log('is it the first occurrence?'), and after the first occurrence put a console.log('its not the first occurrence')
3) Do the same for every occurrence
4) refresh. One of the 'is it the nth occurrence?' won't have a closer, and now you know where the error happened.
For better debugging, you can enable transitions logging by create app with LOG_TRANSITIONS and/or LOG_TRANSITIONS_INTERNAL properties:
window.App = Ember.Application.create({
// Basic logging, e.g. "Transitioned into 'post'"
LOG_TRANSITIONS: true,
// Extremely detailed logging, highlighting every internal
// step made while transitioning into a route, including
// `beforeModel`, `model`, and `afterModel` hooks, and
// information about redirects and aborted transitions
LOG_TRANSITIONS_INTERNAL: true
});
Referenece: http://emberjs.com/guides/understanding-ember/debugging/
Also, you can use canary build which provide detailed error stack:
http://emberjs.com/builds/#/canary
Ember isn't particularly helpful when it comes to errors in the model hook, or the promises it returns. I'm sure I've read in one of the issues (or http://discuss.emberjs.com/ I'm not sure) that this is an open issue in which they're working.
What I do is use the Chrome Developer Tools to debug the issue (instead of just console loggin it). From my experience it's usually:
you're not returning anything in the model hook
an error inside one of the then functions on the promise the model hook returns
I hope it helps you!