I am not able to get chained promises to work as per RSVP documentation. I have a case where I am trying to fetch some data from the server. If for some reason an error occurs, I want to fetch the data from a local file.
I am trying to chain promises for that.
I have created a simplified example. The below example will give an output but is not what I want. http://emberjs.jsbin.com/cobax/3
App.IndexRoute = Em.Route.extend({
model: function() {
return Ember.$.getJSON('http://test.com/search')
.then(undefined, function(errorObj, error, message) {
return new Promise(function(resolve, reject) {
resolve(model);
}).then(function(response) {
console.info(response.articles);
return response.articles;
});
});
}
});
This example is what I want but it wont call the final 'then'. http://emberjs.jsbin.com/cobax/3
App.IndexRoute = Em.Route.extend({
model: function() {
return Ember.$.getJSON('http://test.com/search')
.then(undefined, function(errorObj, error, message) {
return new Promise(function(resolve, reject) {
resolve(model);
});
})
.then(function(response) {
console.info(response.articles);
return response.articles;
});
}
});
Basically I want to handle the server/local response from the last 'then' method. I also want keep all the callbacks in a single level.
What is the error in the second code snipped?
Update
As @marcio-junior mentioned, the jquery deferred was the issue. Here is the fixed bin from him. http://jsbin.com/fimacavu/1/edit
My actual code doesn't return a model object, it makes another getJSON request to a json file. I can't replicate this in a bin as I dont think js bin allows us to host static files. Here is the code but it wont work. It fails due to some js error.
App.IndexRoute = Em.Route.extend({
model: function() {
var cast = Em.RSVP.Promise.cast.bind(Em.RSVP.Promise);
return cast(Ember.$.getJSON('http://test.com/search'))
.then(undefined, function(errorObj, error, message) {
//return Em.RSVP.resolve(model);
return cast(Ember.$.getJSON('data.json'));
})
.then(function(response) {
console.info(response.articles);
return response.articles;
});
}
});
Can you help me with this? These promises are a bit tricky to understand.
Here is the error stack I see
XMLHttpRequest cannot load http://test.com/search. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access. localhost/:1
Error while loading route: index ember-canary-1.7.0.js:3916
logToConsole ember-canary-1.7.0.js:3916
defaultActionHandlers.error ember-canary-1.7.0.js:39681
triggerEvent ember-canary-1.7.0.js:39763
trigger ember-canary-1.7.0.js:42317
Transition.trigger ember-canary-1.7.0.js:42162
(anonymous function) ember-canary-1.7.0.js:42017
invokeCallback ember-canary-1.7.0.js:10498
publish ember-canary-1.7.0.js:10168
publishRejection ember-canary-1.7.0.js:10596
(anonymous function) ember-canary-1.7.0.js:15975
DeferredActionQueues.flush ember-canary-1.7.0.js:8610
Backburner.end ember-canary-1.7.0.js:8082
(anonymous function)
You are returning a RSVP promise to a jquery deferred. And jquery deferreds doesn't have the feature of fulfill a rejected promise. So you need to update your sample to use Em.RSVP.Promise.cast(deferred), to transform a deferred in a RSVP promise, which implements the promises/a+ spec and does what you want:
App.IndexRoute = Em.Route.extend({
model: function() {
return Em.RSVP.Promise.cast(Ember.$.getJSON('http://test.com/search'))
.then(undefined, function() {
return getDefaultData();
})
.then(function(response) {
console.info(response.articles);
return response.articles;
});
}
});
Your updated jsbin