angular updated http promise methods not working where legacy ones do - angularjs

I'm trying to learn the mean stack from the book 'Getting MEAN' which is a little old now, so I'm using more up to date code where applicable. I have just run across an issue that I can't quite solve myself. There is a controller in the book (which uses an older version of angular) written as
var locationListCtrl = function ($scope, loc8rData) {
loc8rData
.success(function (data) {
$scope.data = { locations: data };
})
.error(function (e) {
console.log(e);
});
};
This runs perfectly with the older version of angular, updating it with a more recent version of angular I have the function
let locationListCtrl = ($scope, loc8rData) => {
loc8rData
.then((data) => {
$scope.data = { locations: data };
}, (e) => {
console.log(e);
});
};
This causes an issue with my app and my data is not displaying, and I am getting a [filter:notarray] error, if I remove the filter none of my data is displaying. The part that I am struggling with is that the only thing that has changed is the promise method and the syntax. The data returned by the $http method in loc8rData is the same, assigning it to the scope hasn't changed
$scope.data = { locations: data };
and the browser sees the returned data the same using both methods, which is returned as an array.
So what am I missing, this is driving me mad.
Thanks

The deprecated success() function expects 4 arguments:
data (the body of the response)
status (the status of the response)
headers (the headers of the response)
config (the config object used when sending the request)
The then() function expects a single argument: response. This response object has 4 fields: data, status, headers, config.
So the code should be
locatorData
.then(response => {
$scope.data = { locations: response.data };
}, e => {
console.log(e);
});
Note that I also chose to use locatorData, which is much more readable than loc8rData.

Related

ReactJS & Flux get data from promise

I am trying to get data from server with service function that I found in a template reactjs project. I do recieve a perfectly fine anwser from the server, I can see the arrays are ok while still in the service, but not when handed over to the component that called for it in the first place. At the component I get a promise object, which has the values (I have seen them in console) but I can't access them. What am I missing?
My component has following function:
calculate(dict) {
var results = Service.calc(dict)
.catch((err) => {
var errResp = JSON.parse(err.response);
console.log(errResp);
this.setState({responseErrors: errResp});
});
this.setState({results:results._handler});
}
When I printed the results in to console I saw the Promise object, inside _handler.handler was a value array with my values but I couldn't use them. The error appeared when accessing the results._handler.handler: undefined.
The called service looks like this:
class Service {
calc(dict) {
return this.handleCalculate(when(request({
url: UserConstants.URL,
method: 'POST',
type: 'json',
data: dict
})));
}
handleCalculate(calcPromise) {
return calcPromise.then(
function(data) {
console.log(data); //Success
return data;
}
)
}
Meanwhile I use ajax call directly in the component instead of the service. But I understand that is bad practice, how can I get this right?
Hi basically you put setState in the wrong place. (It sets state right away without waiting for result getting resolved). It should look like this
calculate(dict) {
var results = Service.calc(dict)
.then(results => {
this.setState({results: results});
})
.catch((err) => {
var errResp = JSON.parse(err.response);
console.log(errResp);
this.setState({responseErrors: errResp});
});
}

Can I have, using AngularJS ($http), the following call sequence?

testAngular(); //**(1º)**
function testAngular() {
var uri = 'some_webmethod_url';
var data = {
"key": "anything"
};
var res = $http.post(uri, data);
res.then(function (data) {
console.log(data); //**(2º)**
});
console.log(data); //**(3º)**
}
console.log(data); //**(4º)**
The actual sequence is 1º -- 3º -- 4º -- 2º; Why?
And more importantly, how can I make this in that sequence? (1º -- 2º -- 3º -- 4º)
Since the 'then' is a callback and called asynchronously when the response from the server becomes available (after the POST request is completed). So the statement console.log(data); //**(2º)** will be executed only after the response is received but rest of other processing will continue.
If you want the order that you mentioned, you will have to make those statement as part of the callback. The other option is to make the callbacks synchronous which is not supported out of the box by Angular JS but you can look into the source code and make changes. This SO post might help you in that https://stackoverflow.com/questions/13088153/how-to-http-synchronous-call-with-angularjs
Or a small hack as mentioned in other SO post might help you AngularJs: Have method return synchronously when it calls $http or $resource internally though it's not recommended.
testAngular(); //**(1º)**
function testAngular() {
var uri = 'some_webmethod_url';
var data = {
"key": "anything"
};
var res = $http.post(uri, data);
res.then(function (data) {
console.log(data); //**(2º)**
console.log(data); //**(3º)**
console.log(data); //**(4º)**
});
}

PUT and POST Angularjs

I have an Ionic project with a WCF RESTful service, I want to be able to Insert and Update data. I can already view data with GET method but can't find anything on the internet for PUT and POST. How would I be able to accomplish this?
GET Method
$scope.selectedDist= function() {
$http.get("http://192.168.1.113/Service1.svc/GetAllComp")
.success(function(data) {
var obj = data;
var ar = [];
angular.forEach(obj, function(index, element) {
angular.forEach(index, function(indexN, elementN) {
ar.push({CompID: indexN.CompID, CompName: indexN.CompName});
$scope.districts = ar;
});
});
})
.error(function(data) {
console.log("failure");})
};
Post methods I tried
#1
$scope.insertdata = function() {
var ar = [{'M1':$scope.M1, 'M2':$scope.M2,'M3':$scope.M3,'M4':$scope.M4,'M5':$scope.M5,'M6':$scope.M6,'M7':$scope.M7,'M8':$scope.M8,'M9':$scope.M9,'M10':$scope.M10,}]
$http.post("http://192.168.1.113/Service1.svc/GetAllComp", ar)
.success(function(data)
{
console.log("data inserted successfully")
})
.error(function(data)
{
console.log("Error")
})
#2
$scope.insertdata = function() {
var ar = [{'M1':$scope.M1, 'M2':$scope.M2,'M3':$scope.M3,'M4':$scope.M4,'M5':$scope.M5,'M6':$scope.M6,'M7':$scope.M7,'M8':$scope.M8,'M9':$scope.M9,'M10':$scope.M10,}]
$http ({
url : "localhost:15021/Service1.svc/TruckDetails" ,
Method : "POST" ,
headers : {
'Content-Type' : 'Application / json; charset = utf-8'
},
Data : ar
})
Also Would I need to make a POST or PUT method on my Service as well or can I use the GET methods?
You can use a get method, in combination with a querystring to post and put data but that is not what it was designed for and should be avoided for several reasons such as security.
That being said, it is not that difficult to use post and put in angular and in the following , rather naive service , you can see all that is required to do is passing your data in the service function you're invoking.
.service('MyService', function($http) {
this.postMethod = function(data) {
return $http.post('http://my.url', data);
};
this.putMethod = function(id, data) {
return $http.put('http://my.url/' + id, data);
};
}
So that in your controller you can inject and invoke the service methods with the $scope data that needs to be stored.
After taking a look at your attempts you seem to be using the same url for both get and post: "http://192.168.1.113/Service1.svc/GetAllComp" which actually leads me to believe you haven't thought about implementing these methods on your server. Can you confirm this?
Apart from that, it is always usefull to look at statuscodes when trying to send requests because they provide a great deal of information about the nature of the error that occurs. You can investigate that in either your console or an external program such as Fiddler.
P.S.
Deprecation Notice The $http legacy promise methods success and error
have been deprecated. Use the standard then method instead. If
$httpProvider.useLegacyPromiseExtensions is set to false then these
methods will throw $http/legacy error.

AngularJS - why promises ($q) with $http?

I am learning AngularJS after converting from jQuery for a few years. And some bits are much more intuitive. Some not so much :).
I am trying to get my head around the use of promises, particularly $q in use with $http and there does not seem to be too much information around these two combined that I can find.
Why would I use promises in place of the success/error callback? They both make uses of callbacks in reality, so why is a promise considered better? E.g. I could set up a get(...) function like follows:
function get(url, success, error) {
success = success || function () {};
error = error || function () {};
$http.get(url)
.success(function (data) {
success(data);
})
.error(function (error) {
error(error);
});
}
get('http://myservice.com/JSON/',
function () {
// do something with data
},
function () {
// display an error
}
);
Which is good(?) because it gives me complete control over what is happening. If I call get(...) then I can control any success/errors wherever get is called.
If I convert this to use promises, then I get:
function get(url) {
return $http.get(url)
.then(function (data) {
return data;
},
function (error) {
return error;
});
}
get('http://myservice.com/JSON/')
.then(function (data) {
// do something with data
});
// cannot handle my errors?
Which is condensed, I agree; we also do not have to explicitly worry about the success/error callback, but I seem to have lost control over my error callback for a start - because I cannot configure a second callback to handle an error.
Which means that if I use this function in a service which can be used by multiple controllers, then I cannot update the UI to alert the user to an error.
Am I missing something? Is there a reason why promises is preferred? I cannot find an example why.
Usually you'll deal with asynchronous tasks in Javascript with callbacks;
$.get('path/to/data', function(data) {
console.log(data);
});
It works fine, but start to complicate when you go into whats called the 'callback hell';
$.get('path/to/data', function(data) {
$.get('path/to/data2' + data, function(data2) {
$.get('path/to/data3' + data2, function(data3) {
manipulate(data, data2, data3);
}, errorCb);
}, errorCb);
}, errorCb);
The alternative is working with promises and defered object;
Deferreds - representing units of work
Promises - representing data from those Deferreds
Sticking to this agenda can assist to you in every extreme asynctask case:
You have a regular call that need to get data from the server, manipulate it, and return to the scope
You have multiple calls that each is depending on the precious one (cahin strategy)
You want to send multiple (parallel) calls and handle their success in 1 block
You want your code to be orginized (prevent dealing with handling results on controllers)
Your task is the easiest one to handle with $q and $http
function get(url) {
var deferred = $q.defer();
$http.get(url)
.success(function (data) {
deferred.resolve(data);
})
.error(function (error) {
deferred.reject(error);
});
return deferred.promise;
}
And calling the service function is the same
get('http://myservice.com/JSON/')
.then(function (data) {
// do something with data
});
// cannot handle my errors?
You can handle the error like this:
get('http://myservice.com/JSON/')
.then(function (data) {
// do something with data
},
function (error) {
//do something with error
});
But unfortunately since you have already caught the error then the final error won't be triggered. You will also have the same problem with success.
To get that to work you ned to use $q.
function get(url) {
var deferred = $q.defer();
$http.get(url)
.success(function (data) {
deferred.resolve(data);
})
.error(function (error) {
deferred.reject(error);
});
return deferred.promise;
}
Also there is no need to pass in success and error functions because you can use promises instead.

Exception handling with jsonp requests in angularjs

I have the following code which make seperate requests for jsonp data.
In the code "doRequestA" works fine and returns a result. The issue I have is
I need to catch any errors if they occur. I have tried implementing this in
"doRequestB", but only receive the alert error (I have ommitted the callback from doRequestB).
Here is the fiddle http://jsfiddle.net/a4Rc2/417/
function jsonp_callback(data) {
alert(data.found);
}
function jsonp_example($scope, $http) {
$scope.doRequestA = function () {
var url = "http://public-api.wordpress.com/rest/v1/sites/wtmpeachtest.wordpress.com/posts?callback=jsonp_callback";
$http.jsonp(url);
};
$scope.doRequestB = function () {
var url = "http://public-api.wordpress.com/rest/v1/sites/wtmpeachtest.wordpress.com/posts";
$http.jsonp(url)
.success(function (data) {
alert(data.found);
}).error(function (data, status, headers, config) {
alert('error');
});
};
}
Any advice is greatly appreciated, thanks in advance.
You actually are using $http.jsonp incorrectly in both cases. You just can't see the error in the first case because you are not handling it.
With Angular.js's $http.jsonp method, the callback method is handled automatically. You shouldn't use your own methods in the result string, but rather insert JSON_CALLBACK (exactly as written) into your string. This way, you can handle the response using the promise returned from Angular. If you watch the network activity (say, using Firebug or the developer tools in your browser of choice), you'll see JSON_CALLBACK replaced with something like angular.callbacks._0*.
In the second example, you don't have a callback method defined at all, so the result will always error. There's actually no way for the jsonp result to be handled, since it simply returns the JSON object without a callback method, and the result just is ignored.
Here's a working result: http://jsfiddle.net/tPLaN/1/
The code:
function jsonp_callback(data) {
alert(data.found);
}
function jsonp_example($scope, $http) {
$scope.doRequestA = function() {
var url = "http://public-api.wordpress.com/rest/v1/sites/wtmpeachtest.wordpress.com/posts?callback=JSON_CALLBACK";
$http.jsonp(url).success(function(data) {
jsonp_callback(data);
});
};
$scope.doRequestB = function() {
var url = "http://public-api.wordpress.com/rest/v1/sites/wtmpeachtest.wordpress.com/posts?callback=JSON_CALLBACK";
$http.jsonp(url)
.success(function (data) {
alert(data.found);
}).error(function (data, status, headers, config) {
alert('error');
});
};
}
The only thing I changed was
Correcting the two URLs.
Moving the callback handler on the first method inside the .success() method on the promise.
Believe it or not, the need for JSON_CALLBACK is in the documentation for $http.jsonp, but it's sort of hidden.
* Note, please do not use the replacement for JSON_CALLBACK for anything. It's a private method generated by Angular, I am just showing it to help make more sense of what is happening.

Resources