How to make wrapped jQuery promise fire the reject callback on error? - ajax

I'm wrapping a simple jQuery promise with RSVP and noticed that when I cause an error on purpose the failure callback is never invoked. I assume it's because when you use vanilla jQuery and the callback throws an error, the returned promise will not be moved to failed state (the opposite of the spec).
If I need to use jQuery $.ajax but I want to get true resolve/reject callbacks with RSVP what (if anything) can I do to the example below?
var peoplePromise = new Ember.RSVP.Promise(function(resolve, reject) {
$.getJSON('/api/people/', resolve).fail(reject).error(reject);
});
var catPromise = new Ember.RSVP.Promise(function(resolve, reject) {
$.getJSON('/api/cats/', resolve).fail(reject).error(reject);
});
Ember.RSVP.all([peoplePromise, catPromise]).then(function(things) {
things[0].forEach(function(hash) {
var thing = App.Person.create(hash);
Ember.run(self.people, self.people.pushObject, thing);
});
things[1].forEach(function(hash) {
var wat = hash.toJSON(); //this blows up
var thing = App.Person.create(hash);
Ember.run(self.people, self.people.pushObject, thing);
});
}, function(value) {
alert(value.status + ": promise failed " + value.responseText);
});

Example here: http://www.youtube.com/watch?feature=player_detailpage&v=g5CSaK3HqVA#t=1080
var ajaxPromise = function(url, options){
return Ember.RSVP.Promise(function(resolve, reject) {
var options = options || {};
options.success = function(data){
resolve(data);
};
options.error = function(jqXHR, status, error){
reject([jqXHR, status, error]);
};
$.ajax(url, options);
});
};
var peoplePromise = ajaxPromise('/api/people/',{
dataType: "json"
});
var catPromise = ajaxPromise('/api/cats/',{
dataType: "json"
});
Ember.RSVP.all([peoplePromise, catPromise]).then(function(things) {
things[0].forEach(function(hash) {
var thing = App.Person.create(hash);
Ember.run(self.people, self.people.pushObject, thing);
});
things[1].forEach(function(hash) {
var wat = hash.toJSON(); //this blows up
var thing = App.Person.create(hash);
Ember.run(self.people, self.people.pushObject, thing);
});
}, function(args) {
var jqXHR = args[0];
alert(jqXHR.status + ": promise failed " + jqXHR.responseText);
});
http://emberjs.jsbin.com/aREDaJa/1/

Related

Nodejs - xmlhttprequest promise never finish

module.js
var Promise = require('bluebird');
var XMLHttpRequest = require('xhr2');
function fetchdata(id) {
var url = 'http://www.youtube.com/watch?v=' + id;
return new Promise(function (fulfill, reject) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.onload = function() {
var jsonStr;
try {
fulfill(xhr.response);
} catch (e) {
reject(jsonStr);
}
};
xhr.onerror = function(e) {
reject(e);
};
xhr.send('');
});
}
module.exports = {
getdata: function (videoID) {
return new Promise(function (fulfill, reject) {
if (!videoID) {
reject(new Error('Unable to get video id.'));
return;
}
fetchdata(videoID).then(
function (d) {
console.log( d);
}
);
});
}
};
index.js
var parser = require('./module.js');
parser.getdata("ZI4tRn4dOGg", function (data) {
console.log(data);
}
)
I tried to get youtube view page source code with xmlhttprequest.
BUT above code does not finish. I guess it is waiting for something.
Is problem from bluebird? or xhr2? and why does this code never finish?
Your xhr instance had a memory leak, might be a problem with the library, last publish was a year ago. Bluebird was ok. You can fix the hangup by using node-fetch and dropping in this replacement for fetchdata
const fetch = require('node-fetch')
function fetchdata(id) {
var url = 'http://www.youtube.com/watch?v=' + id;
return fetch(url).then(res => res.text())
}

Is there a way to show "Loading data.." option in Rally Grid(ext JS) while making the Ajax request to load the data?

I am trying to set the message to "Data Loading.." whenever the data is loading in the grid. It is working fine if I don't make an Ajax call. But, when I try to make Ajax Request, It is not showing up the message "Loading data..", when it is taking time to load the data. Can someone please try to help me with this.. Thanks in Advance.
_loadData: function(x){
var that = this;
if(this.project!=undefined) {
this.setLoading("Loading data..");
this.projectObjectID = this.project.value.split("/project/");
var that = this;
this._ajaxCall().then( function(content) {
console.log("assigned then:",content,this.pendingProjects, content.data);
that._createGrid(content);
})
}
},
_ajaxCall: function(){
var deferred = Ext.create('Deft.Deferred');
console.log("the project object ID is:",this.projectObjectID[1]);
var that = this;
console.log("User Reference:",that.userref,this.curLen);
var userObjID = that.userref.split("/user/");
Ext.Ajax.request({
url: 'https://rally1.rallydev.com/slm/webservice/v2.0/project/'+this.projectObjectID[1]+'/projectusers?fetch=true&start=1&pagesize=2000',
method: 'GET',
async: false,
headers:
{
'Content-Type': 'application/json'
},
success: function (response) {
console.log("entered the response:",response);
var jsonData = Ext.decode(response.responseText);
console.log("jsonData:",jsonData);
var blankdata = '';
var resultMessage = jsonData.QueryResult.Results;
console.log("entered the response:",resultMessage.length);
this.CurrentLength = resultMessage.length;
this.testCaseStore = Ext.create('Rally.data.custom.Store', {
data:resultMessage
});
this.pendingProjects = resultMessage.length
console.log("this testcase store:",resultMessage);
_.each(resultMessage, function (data) {
var objID = data.ObjectID;
var column1 = data.Permission;
console.log("this result message:",column1);
if(userObjID[1]==objID) {
console.log("obj id 1 is:",objID);
console.log("User Reference 2:",userObjID[1]);
if (data.Permission != 'Editor') {
deferred.resolve(this.testCaseStore);
}else{
this.testCaseStore = Ext.create('Rally.data.custom.Store', {
data:blankdata
});
deferred.resolve(this.testCaseStore);
}
}
},this)
},
failure: function (response) {
deferred.reject(response.status);
Ext.Msg.alert('Status', 'Request Failed.');
}
});
return deferred;
},
The main issue comes from your Ajax request which is using
async:false
This is blocking the javascript (unique) thread.
Consider removing it if possible. Note that there is no guarantee XMLHttpRequest synchronous requests will be supported in the future.
You'll also have to add in your success and failure callbacks:
that.setLoading(false);

How can I handle a ajax request response in the Flux Architecture?

Looking at the Flux Documentation I can't figure out how the code to a ajax update, and a ajax fetch would fit into the dispatcher, store, component architecture.
Can anyone provide a simple, dummy example, of how an entity of data would be fetched from the server AFTER page load, and how this entity would be pushed to the server at a later date. How would the "complete" or "error" status of request be translated and treated by the views/components? How would a store wait for the ajax request to wait? :-?
Is this what you are looking for?
http://facebook.github.io/react/tips/initial-ajax.html
you can also implement a fetch in the store in order to manage the information.
Here is an example (it is a concept, not actually working code):
'use strict';
var React = require('react');
var Constants = require('constants');
var merge = require('react/lib/merge'); //This must be replaced for assign
var EventEmitter = require('events').EventEmitter;
var Dispatcher = require('dispatcher');
var CHANGE_EVENT = "change";
var data = {};
var message = "";
function _fetch () {
message = "Fetching data";
$.ajax({
type: 'GET',
url: 'Url',
contentType: 'application/json',
success: function(data){
message = "";
MyStore.emitChange();
},
error: function(error){
message = error;
MyStore.emitChange();
}
});
};
function _post (myData) {
//Make post
$.ajax({
type: 'POST',
url: 'Url',
// post payload:
data: JSON.stringify(myData),
contentType: 'application/json',
success: function(data){
message = "";
MyStore.emitChange();
},
error: function(error){
message = "update failed";
MyStore.emitChange();
}
});
};
var MyStore = merge(EventEmitter.prototype, {
emitChange: function () {
this.emit(CHANGE_EVENT);
},
addChangeListener: function (callback) {
this.on(CHANGE_EVENT, callback);
},
removeChangeListener: function (callback) {
this.removeListener(CHANGE_EVENT, callback);
},
getData: function (){
if(!data){
_fetch();
}
return data;
},
getMessage: function (){
return message;
},
dispatcherIndex: Dispatcher.register( function(payload) {
var action = payload.action; // this is our action from handleViewAction
switch(action.actionType){
case Constants.UPDATE:
message = "updating...";
_post(payload.action.data);
break;
}
MyStore.emitChange();
return true;
})
});
module.exports = MyStore;
Then you need to subscribe your component to the store change events
var React = require('react');
var MyStore = require('my-store');
function getComments (){
return {
message: null,
data: MyStore.getData()
}
};
var AlbumComments = module.exports = React.createClass({
getInitialState: function() {
return getData();
},
componentWillMount: function(){
MyStore.addChangeListener(this._onChange);
},
componentWillUnmount: function(){
MyStore.removeChangeListener(this._onChange);
},
_onChange: function(){
var msg = MyStore.getMessage();
if (!message){
this.setState(getData());
} else {
this.setState({
message: msg,
data: null
});
}
},
render: function() {
console.log('render');
return (
<div>
{ this.state.message }
{this.state.data.map(function(item){
return <div>{ item }</div>
})}
</div>
);
}
});
I hope it is clear enough.

Got promise not working

I'm trying to use promise to get in promise2
But if I have an object Widgets with several elements in it...
Why can't I have been able to get my console.log's output
Parse.Cloud.define("extract", function(request, response) {
var user = request.params.user;
var promise = Parse.Promise.as();
[...]
}).then(function() {
return query.find().then(function(results) {
_.each(results, function(result) {
[...]
Widget.objectId = result.id;
Widgets[timestamp] = Widget;
});
return promise;
}).then(function(results) {
for (var key in Widgets) {
var Widget = Widgets[key];
var widget_data = Widgets[key].widget_data;
var promise2 = Parse.Promise.as();
promise2 = promise2.then(function() {
return Parse.Cloud.run('extractWidgetData', {
'widget_data': widget_data,
}).then(function(newresult) {
Widgets[key].data = newresult.data;
console.log('--------WHY NOT HERE ALL TIME ?--------');
});
});
return promise2;
}
}).then(function() {
response.success(Widgets);
},
function(error) {
response.error("Error: " + error.code + " " + error.message);
});
});
});
I'm becoming crazy to run this damn Code
EDIT : I finally followed Roamer's advices to implement something but I'm not sure if it's the good way to work with Promise in series...
Parse.Cloud.define("extract", function(request, response) {
var user = request.params.user;
var Widgets = {};
...
... .then(function() {
return query.find().then(function(results) {
return Parse.Promise.when(results.map(function(result) {
var Widget = ...;//some transform of `result`
Widget.id = ...;//some transform of `result`
var timestamp = createdAtDate.getTime();
...
return Parse.Cloud.run('extractData', {
'widget_data': Widget.widget_data,
}).then(function(newresult) {
Widget.stat = newresult.stats;
return Widget;//<<<<<<< important! This ensures that results.map() returns an array of promises, each of which delivers a Widget objects.
});
}));
}).then(function() {
var promisedWidget = Array.prototype.slice.apply(arguments);
return Parse.Promise.when(promisedWidget.map(function(Widget) {
return Parse.Cloud.run('getWineStats', {
'id': Widget.data.id
}).then(function(stat) {
Widget.stat = stat;
return Widget;
});
}));
}).then(function() {
var promisedWidget = Array.prototype.slice.apply(arguments);
_.each(promisedWidget, function(Widget) {
var createdAtObject = Widget.createdAt;
var strDate = createdAtObject.toString();
var createdAtDate = new Date(strDate);
timestamp = createdAtDate.getTime();
Widgets[timestamp] = Widget;
});
return Widgets;
}).then(function(Widgets) {
response.success(Widgets);
},
function(error) {
response.error("Error: " + error.code + " " + error.message);
});
});
});
First, I echo Bergi's comment on indentation/matching parenthesis.
But ignoring that for a moment, at the heart of the code you have return query.find().then(...).then(...).then(...) but the flow from the first .then() to the second is incorrect. Besides which, only two .then()s are necessary as the code in the first then is synchronous, so can be merged with the second.
Delete the two lines above for (var key in Widgets) { then at least Widgets will be available to be processed further.
Going slightly further, you should be able to do all the required processing of results in a single loop. There seems to be little pont in building Widgets with _.each(...) then looping through the resulting object with for (var key in Widgets) {...}.
In the single loop, you probably want a Parse.Promise.when(results.map(...)) pattern, each turn of the map returning a promise of a Widget. This way, you are passing the required data down the promise chain rather than building a Widgets object in an outer scope.
Do all this and you will end up with something like this :
Parse.Cloud.define("extract", function(request, response) {
var user = request.params.user;
...
... .then(function() {
return query.find().then(function(results) {
return Parse.Promise.when(results.map(function(result) {
var Widget = ...;//some transform of `result`
...
return Parse.Cloud.run('extractWidgetData', {
'widget_data': Widget.widget_data,
}).then(function(newresult) {
Widget.data = newresult.data;
return Widget;//<<<<<<< important! This ensures that results.map() returns an array of promises, each of which delivers a Widget objects.
});
}));
}).then(function() {
//Here, compose the required Widgets array from this function's arguments
var Widgets = Array.prototype.slice.apply(arguments);//Yay, we got Widgets
response.success(Widgets);
}, function(error) {
response.error("Error: " + error.code + " " + error.message);
});
});
});

Get the variable of a json request outside the function (jquery)

I feel pretty stupid asking this but how can I get the variable crdnts outside the function
$(function() {
var coordinates = {
LoadDefault: function() {
$.getJSON('http://api.wipmania.com/jsonp?callback=?', '', function(json) {
var crdnts = json.latitude + "," + json.longitude;
//alert(crdnts);//this works
return crdnts;
});
}
};
alert(coordinates.LoadDefault());//I would like to get the crdnts variable here.
});
or
http://jsfiddle.net/stofke/Lv3YD/
javascript ajax is asynchronous. so you need to use callbacks:
$(function() {
var coordinates = {
LoadDefault: function() {
$.getJSON('http://api.wipmania.com/jsonp?callback=?', '', function(json) {
var crdnts = json.latitude + "," + json.longitude;
call_alert(crdnts); //callback
});
}
};
function call_alert(cr){
alert(cr);
}
coordinates.LoadDefault();
});
You can't. Your Ajax call is asynchronous, so you cannot predict when will it return.
The only thing you can do is doing something with it in the success callback, or set your Ajax to be synchronous if it is a choice (in this case all JS execution will wait until the request is finished).
For example, you can call a function when the Ajax call successfully finished:
$(function() {
var coordinates = {
LoadDefault: function() {
$.getJSON('http://api.wipmania.com/jsonp?callback=?', '', function(json) {
var crdnts = json.latitude + "," + json.longitude;
callSomething(crdnts);
});
}
};
function callSomething(x) {
alert(x);
}
});

Resources