Breeze entityManager calling fail callback even on success - javascript

The entityManager instance is calling fail callback even on success.
Checking the network activity, the requests returns 200 and with expected data.
If I remove the .fail() method from the chain it works just fine, with it I get that the error object is undefined.
My WebAPI is running with CORS enabled and as we're in early development, everything is fully allowed (headers, methods, any origin, credentials).
Here is the JavaScript code:
function getResumoPromocoes() {
var resumoPromocoes = [];
var orderBy = "visualizacoes";
return EntityQuery.from("Promocoes")
.select("id, titulo, descricao, iniciaEm, expiraEm")
.orderBy(orderBy)
.toType("Promocao")
.using(manager)
.execute()
.then(function(data) {
resumoPromocoes = data.results;
log("Resumo das Promoções recebidas", resumoPromocoes.length, true);
return resumoPromocoes;
})
.fail(_queryFailed(error));
}
Is it proper to pass the fail callback after the success one in the .then() method? Same thing with .fail()?

Not sure if this is the issue but the ";" after the then clause is almost certainly an error and the argument to '.fail' needs to be a function not the result of executing a function. So try this instead.
.then(function(data) {
...
})
.fail(_queryFailed);

Related

How do I create a variable with the result from $http in angular?

Im trying to get a json object from a http call with the following line.
var u = $http.get("http://localhost:8580/jettyjspconfiguration-example/sql?loc=locc");
When I log it
console.log(u);
I dont get the json in return
Object { $$state: Object, success: $http/promise.success(), error: $http/promise.error()
How do i just make it return as a json string? Im using it in a factory if that matters. Thanks.
$http.get doesn't return the value which have been sent by API. It only returns the object of HttpPromise. To get the value you need to call the then function on the u
var u = $http.get("http://localhost:8580/jettyjspconfiguration-example/sql?loc=locc");
u.then(function(response){
var yourVar = response.data;
console.log(yourVar);
});
For more see the Documentation
Assigning the http request to a variable doesnot mak the service call. You need to make the call as
var u = $http.get("http://localhost:8580/jettyjspconfiguration-example/sql?loc=locc");
$scope.ResponeData = null;
u.then(function(response){
// Your response will be available here only
$scope.ResponeData = response;
});
You can find more details about the promises and web service call here.
When you perform an HTTP request, this request is not completed instantly, but rather it's completed asynchronously. So what happens is that when the request is made you get a sort of token (a Promise) that you can keep track of while the request is 'in the air'.
This promise is the object you log when you type:
var u = $http.get("http://localhost:8580/jettyjspconfiguration-example/sql?loc=locc");
console.log(u);
To 'keep track' of this promise you can supply it with functions, somewhat similar to event handlers by using the then, error, success, and finally functions.
So here's what happens:
// Start the request and get a promise that an answer will eventually come.
var u = $http.get("http://localhost:8580/jettyjspconfiguration-example/sql?loc=locc");
// The request is handled asynchronously, so all we have now is the promise that
// at some time there will be a result.
console.log(u);
// Assign 'event handlers' to the promise
u.then(function(result) {
// This 'event handler' function is called when the async process completes
// successfully. You can now use the data as you please
doFancyStuffWithResultData(result.data);
}, function(error) {
// This 'event handler' function is called when the async process has an error
console.error('Ohnoz, things went wrong', error);
});
Note that I put 'event handler' in quotes because it helps to think of the functions as like-'event handlers', but there are some differences. Have a look at the documentation for the $q service for more information on what Promises are and how they work.

How to know which $.ajax promise has resolved?

I'm using jQuery ajax to request data which will then be made into different kinds of charts or tables.
I've put the queries I want to run into an object and send the requests. runQuery() returns a jQuery promise. The data returned when the promise is done is correct. [Edit]Since the ajax requests run asynchronously they may not come back in the order they were issued [/EDIT] and I have no way of know which query the returned data was for.
function refreshData(){
for(var key in baseQueries){
runQuery(baseQueries[key])
.done(function(data){
console.log("Query data for "+key);
// want to call different charting functions
// based upon which results are returned
});
}
};
runQuery(obj) { // "public" function
var params = $.extend({},defaults,obj);
return sendRequest(queryUrl,params)
}
sendRequest(url,data,method){ // "private" function
method = method || "GET";
return $.ajax({
type:method,
url:url,
dataType:"json",
data:data
})
.fail(function(error){
console.log(error);
});
}
In this case the console logs the value of key during the last iteration over the baseQueries object. For example if there are three items in my baseQueries object and the the last item in my baseQueries object is
"This-is-the-last-query":"queryparam1,queryparam2,etc"
Then when all three of the ajax calls resolve I get three logs of "This-is-the-last-query". Which is not helpful because it doesn't tell me which query the data belongs to.
This is similar to the idea of the infamous javascript loop issue but I really don't see how the answer of attaching the value to a DOM element could be used here.
How do I match up which query call goes with which promise? How to I pass the key through the ajax call and return it with the promise data.
Edit
Don't think this is a duplicate of the indicated thread. I see how they are related, but not how to use that to solve this. Suggested duplicate doesn't mention jquery, ajax, promises, or asynchronous issues. It is also marked as a duplicate for another thread that doesn't mention any of those things either.
The solution shown either involves using the dom element to hold the information (which doesn't apply here) needed for the onclick or by adding a closure, but I don't see how to do that when there is already data being returned.
If you pass jQuery ajax a parameter that it knows nothing about, it ignores it and you can access it later.
Here we set a parameter for your extra value (mykey) then we have access to it later for the instance we are using:
function refreshData() {
for (var key in baseQueries) {
runQuery(baseQueries[key], key)
.done(function(data) {
console.log("Query data for " + this.myKey);
// "this" here is the ajax for which the promise (ajax) gets resolved,
// and we return that promise so it works here.
// want to call different charting functions
// based upon which results are returned
});
}
};
runQuery(obj,key) { // "public" function
var params = $.extend({}, defaults, obj);
return sendRequest(queryUrl, params,,key)
}
sendRequest(url, data, method, key) { // "private" function
method = method || "GET";
return $.ajax({
type: method,
url: url,
dataType: "json",
data: data,
myKey:key
})
.fail(function(error) {
console.log(error);
});
}
if you want to check if jquery promise is resolved you can check with jqueryPromise.state() which returns either pending, resolved or rejected depending on state.
If you are sending multiple ajax requests and you want to know when they are completed you can put them into array ([$.ajax(...),$.ajax(...)]) and pass it to
$.when like
var requests = [$.ajax(...),$.ajax(...)];
$.when.apply($, requests).done(function() {
console.log('all requests completed');
});
if you want to build something complex with promises I would suggest using bluebird or less complex rsvp

Prevent previous, yet longer-running $http request from returning after most recent request

I just came across a weird situation and wasn't able to find an answer for after some searching.
I have a textbox that I'm using to allow a user to type keywords to filter table data. I have an ng-change directive on the input element which will fire this code:
return $http.get(url).then(function (response) {
return response.data;
});
All of this has worked great, until our tester just found some undesirable behavior in IE11. Here is an example of typing "M-A-T-T" into the textbox in IE10:
As you can see, each subsequent request takes longer than the first so the result of the fourth and final request is the one the controller receives.
Here is the same example of typing "M-A-T-T" into the textbox in IE11.
Inexplicably, the second request takes almost 2 seconds to complete which is after the fourth and final request completed. This results in the results from the "MA" request displaying when the user is expecting the results of the "MATT" request (which is what is currently in their textbox).
How can this be dealt with in Angular? Thanks in advance.
UPDATE
Based on frosty's response, I've implemented the following (in addition to bouncing) which works great:
var cancelDeferred;
var getUsers = function (criteria) {
if (cancelDeferred) {
cancelDeferred.resolve();
}
cancelDeferred = $q.defer();
return $http.get(url, { timeout: cancelDeferred.promise }).then(function (response) {
cancelDeferred = undefined;
return response.data;
});
};
The main challenge, actually, was handling errors when this method is called. The timeout returns an error just like a 500 would return an error. I want to ignore the timeouts and handle the actual errors. Here is my solution for that:
function onError(data, status) {
if (data.data !== null && data.status !== 0) {
//handle error
}
}
Now I'll try to figure out if there is a way to implement this promise-timing-out globally instead of having to alter a ton of $http.get() calls...
In the documentation for $http, it talks about a config object that you can pass as a second argument to the $http.get call, like this:
$http.get(url, config);
In that config, it talks about a "timeout" property that you can set. If you set that property as a Promise, then if you resolve the promise, it will abort the request. Check out the documentation for the description there.
Even if you use a debounce, you will want to use this "timeout" to abort the request.
https://docs.angularjs.org/api/ng/service/$http
So you would do something like this:
var cancelDeferred;
function makeRequest(){
if(cancelDeferred) cancelDeferred.resolve(); //when this gets resolved, the previous request will abort.
cancelDeferred = $q.defer();
return $http.get(url,{timeout:cancelDeferred.promise})
.then(function(res){
cancelDeferred = undefined;
return res;
});
}
So, you pass a promise to the .get request, inside the config object as the "timeout" property. If you resolve this deferred before the response comes back, it will abort the request.

Mocha: assertions within promise not working

So, I'm completely new to mocha, and promises and I was asked to write integration tests, which posts form data to a page, gets an authentication key, and then run tests on the key.
I'm getting the key back properly, which is confirmed by my log statement, but when I run mocha, my test says 0 passing. It doesn't even print out the descriptions for the 'describe' and 'it' statements, implying that they do not work within the promise. Is there away that I can this work, while still giving the assertions access to my authorization key?
require('should');
require('sails');
var Promise = require("promise");
var request = require('request');
describe('Domain Model', function(){
var options = { url:'link',
form:{
username: 'xxxxx#xxxxxx',
password: '0000'
},
timeout: 2000
};
//request auth key
var promise = new Promise(function(resolve,reject){
request.post(options, function(error, response, body){
//body contains the auth key, within a string of JSON
resolve(body);
});
});
//this is where I'm getting lost
promise.then(function(data,test){
var token = (JSON.parse(data))["access_token"];
console.log(token);
describe('Initialize',function(){
it('should be an string', function(){
(token).should.be.type('string');
});
});
});
});
Mocha is not able to find your tests because you're not structuring them correctly. The it() blocks should go immediately within the describe() blocks (and the describe() blocks may be nested within each other as you see fit). If you want to use promises, the promises should go inside the it() blocks, not the other way around. So, as a first pass, the updated code should look something like this (I'm cutting some parts out for brevity):
describe('Domain Model', function(){
var options = { ... };
describe('Initialize',function(){
it('should be an string', function(){
//request auth key
var promise = new Promise(function(resolve,reject){
// ...
});
promise.then(function(data,test){
var token = (JSON.parse(data))["access_token"];
console.log(token);
(token).should.be.type('string');
});
});
});
});
Note that the promise is now contained inside the body of the it(). Mocha should now be able to find your test. However, it won't pass. Why not?
As you probably know, promises are asynchronous. Testing asynchronous code using mocha requires using the done callback - see the guide for more info. Basically, this means the it() block should accept a parameter named done (the name is important!). This done thingy is something that mocha passes in automatically - its presence indicates to mocha that this test contains asynchronous code, and that therefore it has not completed executing until you say so. The way you indicate that your test is done is by executing done, because done is in fact a callback function. You should execute done() at whatever point your test is deemed complete - i.e., at the end of whatever code block is supposed to run last, which in your case is the bottom of the .then() handler for the promise. So, improving upon our last version, the code now looks like this (again, cutting some parts for brevity):
describe('Domain Model', function(){
var options = { ... };
describe('Initialize',function(){
it('should be an string', function(done){
//request auth key
var promise = new Promise(function(resolve,reject){
// ...
});
promise.then(function(data,test){
var token = (JSON.parse(data))["access_token"];
console.log(token);
(token).should.be.type('string');
done();
});
});
});
});
Note that I just added the done parameter to it(), and then I called it at the bottom of the then().
At this point, the code should work, I think... I'm not sure as I'm not able to test it. However, there are a couple more things we could do to improve upon this further.
First, I question your use of promises here. If you had an API for obtaining the access token, then I would opt to have that API return a promise because promises are very convenient for the caller. However, as I'm sure you've noticed, constructing promises can be a bit tedious, and I don't think it adds much value for your code. I would opt to just do this:
describe('Domain Model', function(){
var options = { ... };
describe('Initialize',function(){
it('should be an string', function(done){
//request auth key
request.post(options, function(error, response, body){
//body contains the auth key, within a string of JSON
var token = (JSON.parse(body))["access_token"];
console.log(token);
(token).should.be.type('string');
done();
});
});
});
});
Isn't that so much shorter and sweeter? The code is still asynchronous, so you should still make sure your it() block accepts a done callback, and you should call it when your test has finished.
Now, if you still insist on using promises, then there's one more thing I have to warn you about. What happens if there's an error inside of your .then() handler code? Well, according to the documentation:
If the handler that is called throws an exception then the promise
returned by .then is rejected with that exception.
Do you have a rejection handler for your promise? No. So what does that mean? That means the error will get swallowed up silently. Your test will fail with Error: timeout of 2000ms exceeded, which is because the done handler never got called, but the actual cause of the error won't be shown, and you'll be pulling your hair out trying to figure out what went wrong.
So what can you do? You could use the second parameter to .then() to specify a rejection handler, and in there, you could take advantage of the fact that the done callback that mocha passes in to your test accepts an error argument, so if you call done("something"), your test will fail (which is what we want in this case), and the "something" will be the reason. So here's what that will look like in your case:
describe('Domain Model', function(){
var options = { ... };
describe('Initialize',function(){
it('should be an string', function(done){
//request auth key
var promise = new Promise(function(resolve,reject){
// ...
});
promise.then(function(data){
var token = (JSON.parse(data))["access_token"];
console.log(token);
(token).should.be.type('string');
done();
}, function (err) {
done(err);
});
});
});
});
However, we can do even better. Consider what happens if an error gets thrown from within the rejection handler. Not likely, since you're not doing a whole lot in there - just calling done(err). But what if it does happen? Well, pretty much the same thing - the error will get silently swallowed up, the test will fail with a non-specific timeout error, and you'll be pulling out your hair again. Is there a way we can get that error to bubble up and get rethrown?
As a matter of fact, there is: Both Q and the promise library that you're using have an alternate handler called .done() (not to be confused with mocha's done callback). It's similar to .then(), but with a slightly different behavior around uncaught exceptions. From the documentation:
Promise#done(onFulfilled, onRejected)
The same semantics as .then except that it does not return a promise
and any exceptions are re-thrown so that they can be logged (crashing
the application in non-browser environments)
Perfect, that's exactly what we want. Just be sure to understand when you should use .then(), vs when you should use .done(). The Q API does a fantastic job of explaining (and the promise library you're using has similar behavior - I tested):
The Golden Rule of done vs. then usage is: either return your promise
to someone else, or if the chain ends with you, call done to terminate
it. Terminating with catch is not sufficient because the catch handler
may itself throw an error.
(Note: .catch() appears to be Q-specific, but it's pretty similar to the onRejected callback, which is the second parameter to .then().).
So with that in mind, just replace your last .then() with a .done(). When you use .done(), you can just omit the rejection handler and rely on the promise library to re-throw any unhandled expections, so you will get an error description and a stack trace. With the above in mind, your code now looks like:
describe('Domain Model', function(){
var options = { ... };
describe('Initialize',function(){
it('should be an string', function(done){
//request auth key
var promise = new Promise(function(resolve,reject){
// ...
});
promise.done(function(data){
var token = (JSON.parse(data))["access_token"];
console.log(token);
(token).should.be.type('string');
done();
});
});
});
});
Basically, ignoring the previous code sample, the only difference from the one before that is we're using .done() instead of .then().
Hopefully, this covers most of what you need to get started. There are other things you might want to consider, like potentially retrieving the auth key inside of a before() hook instead of an it() block (because I'm assuming the real thing you're testing is not the retrieval of the key - that's just a prerequisite to test the things you actually want to test, so a hook might be more appropriate - see here). I also question whether or not you should be connecting to an external system from within your tests at all, versus just stubbing it out (that depends on whether these are unit tests or integration tests). And I'm sure you can come up with a better assertion that just checking that token is a string, like using a regex to make sure it matches a pattern, or actually testing a request for a protected resource and making sure that it goes through. But I'll leave those questions for you to think about.

Do Angular JS $http promises to behave like true $q promises?

I'm aware that Angular can handle promises from within controllers. For example:
function MyCtrl($scope) {
$scope.myvar = getDeferredPromise();
}
The main angular digest loop handles this gracefully, assigning whatever value the deferred function finally returns later to myvar.
However, although the $http.get() method returns a promise, I cannot get it to work in this way. For example:
function MyCtrl($scope, $http) {
$scope.myvar = $http.get('/url');
}
The 'promise' the get method returns has a success method which takes a function that is assigned the data that one would wish to assign to myvar.
However, it also has a then method - but that is given the entire response object - not just that data part! This is what seems to end up getting assigned to myvar!
This fiddle may help: http://jsfiddle.net/QKnNC/1/
Am I doing something wrong here? Or is this somehow 'by design'?
ng.$http
The $http service is a function which takes a single argument — a
configuration object — that is used to generate an HTTP request and
returns a promise with two $http specific methods: success and error.
$http returns a promise, so you need to chain then to get the data.
IPService.getV1().then(function (response) {
console.log(response)
$scope.value1 = response.data;
});
then is the general promise function, that takes a success and error callback and you get the resolved value, whatever it may be. success and error are $http specific, and are aliases for then with one exception: they set a bunch of useful arguments rather than just the data. See the source.
It is by design. Your getV2() method is what you want. Since you are using GET, you could save the result of your promise and return that on subsequent calls to getV2():
var v2promise, v2data;
return {
getV2: function() {
if(!v2promise) {
v2promise = $http.get('http://ip.jsontest.com/').then(
function(response) {
v2data = response.data;
return v2data;
});
}
return v2promise;
}
}

Categories