Data from $resource not synchronized to call from HTML - javascript

I'm able to get the print the array returned inside vm.getProduct() in the controller. But this not available in HTML.
Resource:
var DataProvider = function ($resource) {
return $resource('', {}, {
getProductTypeAhead: {
method: 'GET',
isArray: true,
url: '/productinterface?typeahead=:typeAhead',
params: {typeAhead: '#typeAhead'}
}
});
};
module.exports = ['$resource', DataProvider];
Service:
var DataService = function (DataProvider, $scope) {
this.getProductTypeAhead = function (typeAhead, callback) {
DataProvider.getProductTypeAhead({typeAhead: typeAhead},
function (data) {
callback(data);
}, function (data) {
// NOTIFY THE USER THAT THE REQUEST FAILED
callback(null);
});
};
};
module.exports = ['DataProvider', DataService];
Controller:
vm.getProduct = function ($viewValue) {
return DataService.getProductTypeAhead($viewValue, function (response) {
console.log(response);
return cleanResponse(response);
});
};
function cleanResponse(response) {
return JSON.parse(global.angular.toJson(response));
}
HTML:
<input type="text" class="form-control" id="product"
typeahead-min-length="3"
typeahead="product as product.legalName for product in vm.getProduct($viewValue)"
typeahead-template-url="app/main/templates/typeahead-ProductInterface-Template.html"
ng-model="vm.trade.PRODUCT_NAME">
However, if I go for $http.get() approach, I'm able to see the array in HTML.
vm.getProduct1 = function ($viewValue) {
return $http.get('/productinterface?typeahead=' + $viewValue).then(function (response) {
console.log(response.data);
return response.data;
});
};
I checked for the posts to synchronize $resource calls. No luck in that front.
Any pointers on this issue will be much appreciated.
TIA,
Bhushan

If you wanna use $resource with typeahead you can't use the normal callbacks. You need to return a promise.
Return a promise of a $resource request:
vm.getProduct = function ($viewValue) {
return DataService.getProductTypeAhead($viewValue, function (response) {
return response;
}).$promise;
};
Return a promise of a $resource request with callback;
vm.getProduct = function ($viewValue) {
return DataService.getProductTypeAhead($viewValue)
.$promise.then(function(response) {
return doSomethingWith(response);
});
});
};
See example - Asynchronous results

You are returning a promise not the value. That is vm.getProduct is a funciton that returns a promise not data.
vm.getProduct = function ($viewValue) {
return DataService.getProductTypeAhead($viewValue, function (response) {
console.log(response);
return cleanResponse(response);
});
};
function cleanResponse(response) {
return JSON.parse(global.angular.toJson(response));
}
You should set it to any vm property like this
vm.getProduct = function ($viewValue) {
return DataService.getProductTypeAhead($viewValue, function (response) {
console.log(response);
vm.myProperty = cleanResponse(response);
return cleanResponse(response);
});
};

Related

is it possible not to execute the promise (.then ()) in the controller when there is an error in a web request?

I'm currently using a factory called http that when I invoke it, I make a web request. this receives as a parameter the url of the web request.
app.factory('http', function ($http) {
var oHttp = {}
oHttp.getData= function (url) {
var config={
method: 'GET',
url: url
}
return $http(config).then(function(data) {
oHttp.data=data.data;
},function(response) {
alert("problem, can you trying later please?")
});
}
return oHttp;
});
function HelloCtrl($scope, http) {
http.getData('https://www.reddit.com/.json1').then(function(){
if(http.data!=undefined){
console.log(http.data)
}
})
}
I would like the promise not to be executed on the controller if the result of the web request is not satisfied or there is a problem. is there any better solution? I want to avoid doing this every time I make a web request, or do not know if it is the best way (see the if):
//I am putting "1" to the end of the url to generate an error.
http.getData('https://www.reddit.com/.json1').then(function(){
//validate that the result of the request != undefined
if(http.data!=undefined){
alert(http.data.kind)
}
})
In my real project I make n web requests using my factory http, I do not want to do this validation always. I do not know if I always have to do it or there is another solution.
this is my code:
https://plnkr.co/edit/8ZqsgcUIzLAaI9Vd2awR?p=preview
In rejection handlers it is important to re-throw the error response. Otherwise the rejected promise is converted to a successful promise:
app.factory('http', function ($http) {
var oHttp= {};
oHttp.getData= function (url) {
var config={
method: 'GET',
url: url
}
return $http(config).then(function(response) {
̶o̶H̶t̶t̶p̶.̶d̶a̶t̶a̶=̶r̶e̶s̶p̶o̶n̶s̶e̶.̶d̶a̶t̶a̶;̶
return response.data;
},function(response) {
alert("problem, can you trying later please?")
//IMPORTANT re-throw error
throw response;
});
}
return oHttp;
});
In the controller:
http.getData('https://www.reddit.com/.json1')
.then(function(data){
console(data)
}).catch(response) {
console.log("ERROR: ", response.status);
});
For more information, see You're Missing the Point of Promises.
In Service
app.factory('http', function ($http) {
var oHttp = {}
oHttp.getData= function () {
return $http({
method: 'GET',
url: 'https://www.reddit.com/.json1'
});
}
return oHttp;
});
In controller
function HelloCtrl($scope, http) {
var httpPromise = http.getData();
httpPromise.then(function(response){
console.log(response);
});
httpPromise.error(function(){
})
}
So I tried this in codepen having ripped your code out of plinkr
https://codepen.io/PocketNinjaDesign/pen/oGOeYe
The code wouldn't work at all...But I changed the function HelloCtrl to a controller and it seemed happier....?
I also set response.data to default to an empty object as well. So that way if you're populating the data in the page it will be empty if nothing arrived. You can then in some instances on the site check the length if it's really required.
app.factory('http', function ($http) {
var oHttp = {}
oHttp.data = {};
oHttp.getData= function (url) {
var config = {
method: 'GET',
url: url
}
return $http(config).then(function(response) {
oHttp.data = response.data || {};
}, function(response) {
alert("problem, can you trying later please?")
});
}
return oHttp;
});
app.controller('HelloCtrl', function($scope, http) {
http.getData('https://www.reddit.com/.json').then(function(){
alert(http.data.kind);
})
});

How to call nest factory in Angularjs?

Hi I am developing web application in angularjs. I have requirement below. I have one factory. I have added code snippet below.
myapp.factory('sadadpaymentapi', ['$http', '$cookieStore', 'cfg', 'ScrollFunction', 'leaselisting', function ($http, $cookieStore, cfg, ScrollFunction, leaselisting) {
var sadadpaymentapiobject = {};
var baseurl = cfg.Baseurl;
var LoginID = $cookieStore.get("LoginID");
var cookiePreferredLanguage = $cookieStore.get('PreferredLanguage');
var urlapi = baseurl + "api/ServiceRequest/CreateRSSedad/";
sadadpaymentapiobject.callsadad = function (PaymentType) {
leaselisting.leaselisting().then(function (response) {
//Problem in calling
}, function (error) { });
var request = {
url: urlapi,
method: 'POST',
data: {
SRActivityID: LoginID,
PaymentType: PaymentType,
PaymentAmount: "100"
},
headers: ScrollFunction.getheaders()
};
return $http(request);
}
return sadadpaymentapiobject;
}]);
Here is my second factory leaselisting
myapp.factory('leaselisting', ['$http', '$cookieStore', 'cfg', 'ScrollFunction', function ($http, $cookieStore, cfg, ScrollFunction) {
var leaselistingobject = {};
var baseurl = cfg.Baseurl;
var LoginID = $cookieStore.get("LoginID");
var cookiePreferredLanguage = $cookieStore.get('PreferredLanguage');
leaselistingobject.leaselisting=function(){
var requestObj = {
url: "api/ServiceRequest/GetROLSPSRLeaseList/",
data: {
LoginID: LoginID,
RSAccountNumber: $cookieStore.get("AccountNumber")
},
headers: ScrollFunction.getheaders()
};
$http(requestObj).then(function (response) {
}, function (error) {
});
}
return leaselistingobject;
}]);
I have found error in below line
leaselisting.leaselisting().then(function (response) { //Problem in calling
}, function (error) { });
May i am i doing anything wrong in the above code? May i know is it possible to call one factory from another? The response i get from leaselisting i want to pass it in callsadad function of sadadpaymentapi. So can someone hep me in the above code? I am getting error Cannot read property 'then' of undefined in the leaselisting.leaselisting().then(function (response) {},function(error){});
Also is there any way I can directly inject factory like payment amount: inject factory something like this?
I assume, that leaselistingobject.getValue is an asynchronous function.
So first of get your value :
leaselistingobject.getValue = function(){
var requestObj = {
url: "api/ServiceRequest/getValue/"
};
return $http(requestObj).then(function (response) {
return response.data;
});
}
And then use it. To let all async actions finish we use angulars $q.Here you can find a small tutorial.
myapp.factory('sadadpaymentapi', ['$http', '$cookieStore', 'cfg', 'ScrollFunction', 'leaselisting', '$q',function ($http, $cookieStore, cfg, ScrollFunction, leaselisting, $q) {
var sadadpaymentapiobject = {};
var baseurl = cfg.Baseurl;
var LoginID = $cookieStore.get("LoginID");
var cookiePreferredLanguage = $cookieStore.get('PreferredLanguage');
var urlapi = baseurl + "api/ServiceRequest/CreateRSSedad/";
sadadpaymentapiobject.callsadad = function (PaymentType) {
var leastListingPromise = leaselisting.leaselisting();
var getValuePromise = leaselisting.getValue();
$q.all([leastListingPromise, getValuePromise]).then(function (responses) {
//Here you have both responses in an array
var request = {
url: urlapi,
method: 'POST',
data: {
SRActivityID: LoginID,
PaymentType: PaymentType,
PaymentAmount: responses[1]
},
headers: ScrollFunction.getheaders()
};
return $http(request);
});
}
return sadadpaymentapiobject;
}]);
To make leaselisting() return the response of the request change the end of the function from
$http(requestObj).then(function (response) {
}, function (error) {
});
to
return $http(requestObj).then(function (response) {
return response.data;
}, function (error) {
});
If wont do anything about possible errors you can omit the error function part:
return $http(requestObj).then(function (response) {
return response.data;
});

Promise Angularjs 1.6 How can I force function to wait for api response

Im using this plugin: http://www.codingdrama.com/bootstrap-markdown/
I want to hook the onPreview
So on onPreview i try to make my api call:
app.directive("markdowntextarea",function ($http, $q) { // inject $q
return {
link: function (el_scope, element, attr) {
element.markdown(
{
autofocus: false,
savable: false,
onPreview: function (e) {
var deferred = $q.defer();
if (e.isDirty()) {
var originalContent = e.getContent();
$http({
url: '/api/markdown/',
data: {"body": originalContent, "actual_format": "md"},
method: 'POST'
}).then(function successCallback(response) {
console.log("successCallback", response.data.content);
deferred.resolve(response.data.content);
}, function errorCallback(response) {
console.log("errorCallback");
deferred.reject("error");
});
} else {
deferred.resolve("");
}
return deferred.promise;
}
}
);
}
}
});
Console:
successCallback from api!!!
I got success response from api, the response.data.content is what I want to use. The problem here is the return deferred.promise; always return the original value. What can I do here? I'm really new in angularjs
With promises you can't return values at once, usually you return promise object called promise handle and using 'then' clause you wait for promise to resolve(successfully) or reject(failure).
In your case if you want to wait for response and then do something I suggest you call onPreview and use its then clause like:
onPreview(e).then(function(response){}, function(error){});
onPreview is already returning promise which should be thenable.
After Edit:
So onPreview is API method and is expecting a text not promise, now what you can do is define a function like makePreview or something:
function makePreview(e) {
var deferred = $q.defer();
if (e.isDirty()) {
var originalContent = e.getContent();
$http({
url: '/api/markdown/',
data: {"body": originalContent, "actual_format": "md"},
method: 'POST'
}).then(function successCallback(response) {
console.log("successCallback", response.data.content);
deferred.resolve(response.config.data.body);
}, function errorCallback(response) {
console.log("errorCallback");
deferred.reject("error");
});
} else {
deferred.resolve("");
}
return deferred.promise;
}
and then your onPreview should look like this:
autofocus: false,
savable: false,
onPreview: function (e) {
makePreview(e).then(function(response){
e.setContent(response);
return response;
}, function(error){
return error;
});
}
I hope this helps :)
You cannot write angular in absolute sync way. Use the response in callback.
If you need to control api requests' order, or wait for multiple requests, see doc of $q

Angular $http get works in browser but not on device - Ionic

I have a factory returning an object calling an internal resource containing JSON as so:
.factory('cardFactory', function ($q, $http) {
return {
getOtherStuff: function () {
var deferred = $q.defer(),
httpPromise = $http.get('/static/cards.json');
httpPromise.then(function (response) {
deferred.resolve(response);
}, function (error) {
console.error(error);
});
return deferred.promise;
}
};
});
In my controller I call it like this:
var cardSuccess = function(data, status, headers, config) {
$scope.cards = data.data;
};
cardFactory.getOtherStuff()
.then(cardSuccess, cardError);
In the browser $scope.cards in populated but on the device it doesn't populate.
Any ideas why?
Hmm.., not sure.
I have it in a different way in my Ionic app, working great.
.factory('cardFactory', function ( $http ) {
var promise;
var cards = {
getOtherStuff: function() {
if ( !promise ) {
// $http returns a promise, which has a then function, which also returns a promise
promise = $http.get( '/static/cards.json' ).then(function (response) {
// The then function here is an opportunity to modify the response
// The return value gets picked up by the then in the controller.
return response.data;
});
}
return promise; // Return the promise to the controller
}
};
return cards;
})
Then, on the controller, calling it by:
$scope.getData = function() {
// Call the async method and then do stuff with what is returned inside our own then function
cardFactory.getOtherStuff().then(function(d) {
$scope.cards= d;
});
}
$scope.getData();
Hope it helps.
[EDIT:] Could it be the $http.get url, being relative? Have you tried with an absolute url?
Replace $scope.cards=data.data with "$scope.cards=data"
var cardSuccess = function(data, status, headers, config) {
$scope.cards = data;
};
try removing the leading slash in your url for $http. Try using 'static/cards.json' instead of '/static/cards.json'
I actually had the same problem and this fixed it for me. Hope it helps!

AngularJS: transform response in $resource using a custom service

I am trying to decorate the returned data from a angular $resource with data from a custom service.
My code is:
angular.module('yoApp')
.service('ServerStatus', ['$resource', 'ServerConfig', function($resource, ServerConfig) {
var mixinConfig = function(data, ServerConfig) {
for ( var i = 0; i < data.servers.length; i++) {
var cfg = ServerConfig.get({server: data.servers[i].name});
if (cfg) {
data.servers[i].cfg = cfg;
}
}
return data;
};
return $resource('/service/server/:server', {server: '#server'}, {
query: {
method: 'GET',
isArray: true,
transformResponse: function(data, header) {
return mixinConfig(angular.fromJson(data), ServerConfig);
}
},
get: {
method: 'GET',
isArray: false,
transformResponse: function(data, header) {
var cfg = ServerConfig.get({server: 'localhost'});
return mixinConfig(angular.fromJson(data), ServerConfig);
}
}
});
}]);
It seems I am doing something wrong concerning dependency injection. The data returned from the ServerConfig.get() is marked as unresolved.
I got this working in a controller where I do the transformation with
ServerStatus.get(function(data) {$scope.mixinConfig(data);});
But I would rather do the decoration in the service. How can I make this work?
It is not possible to use the transformResponse to decorate the data with data from an asynchronous service.
I posted the solution to http://jsfiddle.net/maddin/7zgz6/.
Here is the pseudo-code explaining the solution:
angular.module('myApp').service('MyService', function($q, $resource) {
var getResult = function() {
var fullResult = $q.defer();
$resource('url').get().$promise.then(function(data) {
var partialPromises = [];
for (var i = 0; i < data.elements.length; i++) {
var ires = $q.defer();
partialPromisses.push(ires);
$resource('url2').get().$promise.then(function(data2) {
//do whatever you want with data
ires.resolve(data2);
});
$q.all(partialPromisses).then(function() {
fullResult.resolve(data);
});
return fullResult.promise; // or just fullResult
}
});
};
return {
getResult: getResult
};
});
Well, Its actually possible to decorate the data for a resource asynchronously but not with the transformResponse method. An interceptor should be used.
Here's a quick sample.
angular.module('app').factory('myResource', function ($resource, $http) {
return $resource('api/myresource', {}, {
get: {
method: 'GET',
interceptor: {
response: function (response) {
var originalData = response.data;
return $http({
method: 'GET',
url: 'api/otherresource'
})
.then(function (response) {
//modify the data of myResource with the data from the second request
originalData.otherResource = response.data;
return originalData;
});
}
}
});
You can use any service/resource instead of $http.
Update:
Due to the way angular's $resource interceptor is implemented the code above will only decorate the data returned by the $promise and in a way breaks some of the $resource concepts, this in particular.
var myObject = myResource.get(myId);
Only this will work.
var myObject;
myResource.get(myId).$promise.then(function (res) {
myObject = res;
});

Categories

Resources