Angular $resource then not returning data - javascript

I have this simple app witha factory and a controller:
angular.module('AppName', ['ngResource'])
.factory('apiData', ['$resource', function ($resource) {
var apiRequest = $resource("https://live.reddcoin.com/api/addr/:address/balance");
return {
full: function(address){
return apiRequest.get({address: address}).$promise
.then(
function(data){ console.log(data); return data;},
function(){ return 'error'; }
);
}
}
}])
.controller('TwoController', function($scope, apiData){
$scope.price = apiData.full('RszZrK51ur5G67y3Wy6niTnawdYYdBRZEq').then(function(data){console.log(data); return data;});
});
The then sections in both factory and controller not returning data from the api resource. Instead it returns e { $promise=Promise, $resolved=true, toJSON=function(), more...} as can be seen in the console.
The url from the example api resource:
https://live.reddcoin.com/api/addr/RszZrK51ur5G67y3Wy6niTnawdYYdBRZEq/balance
And the example on jsfiddle

I'm not sure why $resource doesn't include data(not in object format) inside object return by promise, It display result like below
e {$promise: Promise, $resolved: true} // 1003021043401956 isn't included there
I think get request is expecting object returned from the server. So if it doesn't return an object, then it will not include the same in response
There are 2 ways to solve this problem.
Do return data in object format like {'data': '1003021043401956'}
Create your own get request object inside resource, that will modify before it returns promise object.
var apiRequest = $resource("https://live.reddcoin.com/api/addr/:address/balance", {}, {
get: {
method: 'GET',
transformResponse: function(response){
return {data: response}; //creating object
}
}
});
Fiddle

Try this:
.controller('TwoController', function($scope, apiData){
apiData.full('RszZrK51ur5G67y3Wy6niTnawdYYdBRZEq').then(function(data){
console.log(data);
$scope.price = data;
});
});
Remember that promises are chained. So eventhough you return data in the success callback, the result of then is still a promise (with data as the inner result).
Working code snippet:
angular.module('AppName', ['ngResource'])
.factory('apiData', ['$resource', function ($resource) {
var apiRequest = $resource("https://live.reddcoin.com/api/addr/:address/balance");
return {
full: function(address){
return apiRequest.get({address: address}).$promise
.then(
function(data){ console.log(data); return data;},
function(){ return 'error'; }
);
}
}
}])
.controller('TwoController', function($scope, apiData){
apiData.full('RszZrK51ur5G67y3Wy6niTnawdYYdBRZEq').then(function(data){console.log(data); $scope.price = data;});
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://code.angularjs.org/1.2.23/angular-resource.min.js"></script>
<div ng-app="AppName" ng-controller="TwoController">{{price}}</div>

Related

Change data in Service

I have a service that grabs JSON from a URL and I would like to alter that data but I cant seem to do it. Right now I change this in the controller but this seems messy with the scope not reaching places I would like.
//SERVICE
app.service("servers", function ($http, $q)
{
// Grab json
var deferred = $q.defer();
$http.get('http://www.mocky.io/v2/58bea87e260000c318f07bfd').then(function (data)
{
deferred.resolve(data);
});
this.getItems = function ()
{
return deferred.promise;
}
})
// CONTROLLER
.controller("AppCtrl", function ($scope, servers, geoIP) {
var promise = servers.getItems();
promise.then(function (data)
{
$scope.items = data.data.items;
});
$scope.getSelectedItem = function() {
return servers.selectedItem;
}
$scope.selectServer = function(item)
{
servers.selectedItem = item;
servers.selectedItem.refactored_match_state = lowerCamelCaseUnderscoreRefactor(servers.selectedItem.session.attributes.match_state);
}
//COMPONENT/TEMPLATES
//dbServerTable
<tr data-ng-repeat="item in items | filter:search | orderBy:'name'" data-ng-click="selectServer(item)">
<td>{{item.display_name}}</td>
</tr>
//dbServerInfoSidebar
<li>{{getSelectedItem().refactored_match_state}}</li>
Could anyone show me with code how to alter data in a service that can be used anywhere by any controller that can access that service
The way the service has been coded is an anti-pattern and should be avoided. Refer this link.
Change your service like below and make modifications to the data before you return the data within the .then function.
app.service("servers", function ($http)
{
this.getItems = function ()
{
return $http.get('http://www.mocky.io/v2/58bea87e260000c318f07bfd')
.then(function (data)
{
// **** Modify data here ****
return data;
});
}
})
You can use transformResponse property of $http
service;
You can modify your data before resolving the promise
deferred.resolve(data);.
Are you trying to do something like:
app.service("servers", function ($http, $q)
{
this.parseData = data => {
//modify data;
return data;
};
this._request = $http.get('http://www.mocky.io/v2/58bea87e260000c318f07bfd')
.then(this.parseData);
this.getItems = () => this._request;
});
You don't need to use deferred at all. It's unnecessary. $http returns a promise for you. If you want to alter any data, you just need to chain after the request and return the modified data in the chained method.
app.service('services',['$q','$http','$rootScope',function($q,$http,$rootScope){
var obj ={};
obj.getData =function(x){
var defer = $q.defer();
$http.get('http://www.mocky.io/v2/58bea87e260000c318f07bfd')
.then(function(response){
defer.resolve(response);
},function(error){
defer.reject(error);
});
return defer.promise;
}
return obj;
}])
app.controller('ctrl',function($scope,services){
$scope.getItems = function(){
services.getData()
.then(function(response){
$scope.Items=response.data;
},function(error){
console.log(error);
});
}
})

angularJS closure causes $HTTP.get to not return my array of JSON objects

I have the following 3 methods in my module.factory dataservice I am using Angular 1.5
getCannedJSON . This function works as intended and i would like the others to behave the same way. I copy and pasted the JSON i got from my webAPI in postman and put this in to the function. It returns an array of objects like i want.
getDataFromAPI. For some reason I cannot get this function to return the response. The console.log(response) has exactly the data I want aka the same data as getCannedJSON. Instead it returns a d {$$State: object} any idea how i could alter this code to change have it return in the same format as the getCannedJson method?
getDataFromApiWithDynamicUrl this is no different than the above method but it will take a dyanmic url for the web api. It workds fine minus it not returning an array list of json objects it instead returns the same $$State object.
I would like getDataFromAPI to return the same array of all the objects in the json request like getCannedJson does. Any ideas where I am messing up. Below is a screenshot of the two different types of objects they are returning via console.log I would like the data at the bottom to look like the data at the top.
The code for the dataService module factory is below
(function (module) {
'use strict';
DataService.$inject = ['$http', '$q'];
function DataService($http, $q) {
var getDataFromAPI = function () {
var returnthis;
return $http({ //this top level returns instead
url: "http://localhost:34183/api/quality/month",
dataType: 'json',
method: 'GET',
}).success(function (response) {
console.log("This Response shown below is pefect! but it wont return....");
console.log(response);
return (response);//This never returns
}).error(function(error){
console.log(error);
});
return returnthis;
};
var getDataFromApiWithDynamicUrl = function (pathurl) { // this is version 2 of the method i want to work where i can dynamically change the url to the path
return $http.get(pathurl);
};
var getCannedJSON = function ($http) {
return [{
"hockeyTeam": "Sharks",
"PlayoffRecord": {
"wins": "0"
},
},
{
"hockeyTeam": "Pengiuns",
"PlayoffRecord": {
"wins": "1"
},
}
];
};
return {
getDataFromAPI: getDataFromAPI,
getDataFromApiWithDynamicUrl: getDataFromApiWithDynamicUrl,
getCannedJSON: getCannedJSON
};
}
module.factory('DataService', DataService);
})(angular.module('MyCoolModule'));
below is the code where i call these methods to consume the JSON data in my controller.
(function (module) {
'use strict';
hockeyViewController.$inject = ['DataService'];
function hockeyViewController(DataService) {
var vm = this;
vm.headers = [
{ name: 'Hockey Team', key: 'hockeyTeam' },
{ name: 'Record', key: 'PlayoffRecord'}
];
vm.cannedData = angular.copy(DataService.getCannedJSON());
vm.getDataFromAPI = DataService.getDataFromAPI();
vm.getDataFromAPIwithCustomURL = [];
DataService.getDataFromApiWithDynamicUrl("http://localhost:34183/api/quality/month").then(function(response){
console.log("this response should work - and it does it in the right format");
console.log(response.data);// this looks perfect
vm.getDataFromAPIwithCustomURL = response.data;
return response.data;
}, function (error) {
console.log(error);
});
vm.testMonthResults2 = angular.copy(DataService.getDataFromApiWithDynamicUrl("http://localhost:34183/api/quality/month"));
console.log("canned json Data- works great");
console.log(vm.cannedData);// this works perfectly
console.log("this is the data results with dynamic url - returns wrong object the $$state ");
console.log(vm.getDataFromAPI);// returns $$state not array of objects
console.log(vm.getDataFromAPIwithCustomURL); // this returns [] which is wrong
console.log(DataService.getDataFromApiWithDynamicUrl("http://localhost:34183/api/quality/month"));
// this doesnt work either
}
function reportTabularViewDirective() {
return {
restrict: "E",
controller: hockeyViewController,
controllerAs: 'vm',
bindToController: true,
scope: {
},
templateUrl: "app/widgets/hockey-view.html"
};
}
module.directive('hockeyView', hockeyViewDirective);
})(angular.module('MyCoolModule'));
Can try this one
var getDataFromAPI = function () {
return $http({
url: "/api/quality/month", // try using relative path
dataType: 'json',
method: 'GET',
}).then(function(response) {
console.log(response);
return respose.data;
}, function(error) {
console.log(error);
return [];
});
};
But better to use like: service return only promise and in controller use then function to handle response
In service:
var getDataFromAPI = function() {
return $http.get('/api/quality/month');
};
in controller:
DataService.getDataFromAPI().then(function(response) {
console.log(response.data);
}, function(error) {
console.log(error);
});
You get a $promise object by calling DataService.getDataFromAPI(). You need to handle the $promise object to get the response.
DataService.getDataFromAPI().then(function(response) {
// console.log(response);
})
The same applies when you getDataFromApiWithDynamicUrl() function.
For more info, see doc:
$http
$q

angular factory for $http service makes call twice

I created an angular factory for $http service. I am getting the response and able to use the same in the controller but the problem is, when i check the network tab in the browser, the http request is made twice
Factory:
app.factory('myService', function ($http, $q) {
var deferred = $q.defer();
var responseData = null;
var obj = {};
obj.getData = function(){
$http.get('test.json').success(function(response){
responseData = response;
deferred.resolve(responseData);
}).error(function(response){
deferred.reject(responseData);
});
return deferred.promise;
}
obj.myData = function(){
return responseData;
}
return obj;
});
Controller:
app.controller('myController', function($scope,myService){
myService.getData().then(function(){
$scope.myDetails = myService.myData();
});
});
what's wrong in my approach. Please provide me a solution
The way you are making your caching scenario is quite complicated and not really helpful. How do you know if data has already been loaded?
Maybe you can create a simple Caching Service to handle your caching at a single point (nr of code lines will go down).
angular.module("YourApp").factory("CachingService", [
"$q",
"$http",
function ($q, $http,) {
var cache = {};
return {
getFromCache: getFromCache
};
function getFromCache(url) {
var deferred = $q.defer();
if (cache[url]) {
deferred.resolve(cache[url]);
} else {
return $http.get(url).then(function (result) {
cache[url] = result;
return result;
});
}
return deferred.promise;
}
}
]);
And then, you simply call it inside your other service :
angular.module("YourApp").factory("myService", [
"CachingService",
function(CachingService){
return {
getData: getData
};
function getData(){
return CachingService.getFromCache("test.json");
}
}
]);
And then, inside your controller :
app.controller('myController', function($scope,myService){
myService.getData().then(function(result){
$scope.myDetails = result.Data;
});
});
you can return $http not deferred.promise

How to pass data from factory to controller in angular js?

I have one factory contains save customer function.On success I want to pass its response in controller so that i can update the view.
Factory
sampleApp.factory("authFactory", function($location, $http, transformRequestAsFormPost) {
return {
saveCustomer: function(data) {
var request = $http({
method: "post",
url: "webservice/ws.php?mode=saveCustomer",
transformRequest: transformRequestAsFormPost,
data: data
});
request.success(
function(response) {
console.log(response);
}
);
}
};
});
Controller
sampleApp.controller('customerController', function($scope, testService,authFactory,$http) {
$scope.addCustomer = function() {
var data = {name: $scope.customerName,city: $scope.customerCity};
// Calling Factory Function
authFactory.saveCustomer(data);
// How to fetch response here
}
});
Please help me to solve that problem
Thanks
Various ways, the first one that comes to mind is something like this:
//in your factory
return {
saveCustomer: function(data) {
var request = $http({...});
return request;
}
}
//in your controller
authFactor
.saveCustomer(data)
.success(function() {
//update controller here
})
You are working with "promises" here. You can do a few different things depending on what you return from your service method.
One thing you can do is simply return the promise and handle it in your controller.
service:
return {
saveCustomer: function(data) {
return $http({...});
}
}
contoller:
authFactor.saveCustomer(data).success(function(customer) {
$scope.customer = customer;
})
Another thing you can do is return an object reference and put it on your scope. When the object is filled, it will be updated in your scope.
service:
return {
saveCustomer: function(data) {
var customer = {};
$http({...}).success(function(data){
angular.copy(data, customer);
});
return customer;
}
}
controller:
$scope.customer = authFactor.saveCustomer(data);
The advantage of this second way is that most of your logic stays in your service. You controller stays simple and doesn't have to know about promises or handle them.

AngularJS: Working with callbacks and promises

I am unable to wrap my brain around the concept of asynchronous requests.
I have a controller for my view, which is creating an object instance from a provider:
va.controller('VaCtrl',function($scope,$shipment){
$scope.shipment = $shipment.Shipment();
});
The provider:
Shipment.provider('$shipment',function(){
this.$get = function($http){
function Shipment(){
}
Shipment.prototype.fetchShipment = function(){
var shipment = undefined;
$http.post('../sys/core/fetchShipment.php',{
// some data to POST
}).then(function(promise){
shipment = promise.data;
});
return shipment;
};
return {
Shipment: function(){
return new Shipment();
}
}
}
});
My goal is to get access to the data from Shipment.prototype.fetchShipment() inside my controller. My approach:
$scope.fetchShipment = function(){
var shipment = $scope.shipment.fetchShipment();
console.log(shipment); // undefined
};
However, this will return undefined.
I read about $q, and defers, promises and callbacks, and now i am like WTF; all i want to do is to push the retrieved data to my controller, what is the best possible way to do so?
You should modify your code as shown below to return the promise from fetchshipment directly, and then use then() inside your controller.
Shipment.prototype.fetchShipment = function(){
return $http.post('../sys/core/fetchShipment.php',{
// some data to POST
})
};
$scope.fetchShipment = function(){
var shipment = $scope.shipment.fetchShipment().then(function(data){;
console.log(data);
});
};
Explanation to Code :
Calling $http return a promise which is resolved when you get the data from the server. In the code above, I have returned $http.post from service function which returns a promise. So in the controller you are waiting for promise to be resolved, and when the promise is resolved, the result is logged to the console.
Read about more promise documentation on angular:
http://docs.angularjs.org/api/ng.$q
http://docs.angularjs.org/api/ng.$http
Just the give you an example how to get your example working with your own promise.
It's much more simple if you use $http builtin promise, so it's an $q-example:
angular.module('myApp', []).controller("myAppCtrl", function ($scope, $shipment) {
$shipment.Shipment().fetchShipment().then(function (shipment) {
$scope.shipment = shipment
});
}).provider('$shipment', function () {
this.$get = function ($http, $q) {
function Shipment() {
}
Shipment.prototype.fetchShipment = function () {
var defered = $q.defer();
demodata = {name: "jan", id:8282};
$http.post('/echo/json/', 'json=' + encodeURIComponent(angular.toJson(demodata)), {
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
}
}).then(function (response) {
//resolve promise
defered.resolve(response.data);
});
return defered.promise;
};
return {
Shipment: function () {
return new Shipment();
}
}
}
});
<div ng-controller="myAppCtrl">{{shipment}}</div>
JSFiddle (use JSFiddle echo-service as data provider):
http://jsfiddle.net/alfrescian/ayke2/
More about promises:
http://blog.parse.com/2013/01/29/whats-so-great-about-javascript-promises/
http://www.egghead.io/video/o84ryzNp36Q
AngularJS : Where to use promises?
stackoverflow.com/questions/15604196/… egghead.io/video/o84ryzNp36Q

Categories