I am trying to get data back from a web service, I have to approaches the first is calling the data from the controller which works here is the code
$http({
method: 'POST',
url: 'https://url_json.php',
headers: {'Content-Type': 'application/x-www-form-urlencoded; charset-UTF-8'},
transformRequest: function(obj) {
var str = [];
for(var p in obj)
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
return str.join("&");
},
data: paramsVal
}).then(function(response){
$scope.myData = response.data.PlaceDetailsResponse.results[0].first_name;
console.log('my data',$scope.myData);
});
}
but I would like to share the data between controllers so I read service is the best options, so in my services.js I have:
.factory('userService', function($http){
return {
getUsers: function(){
return $http.post("https://url_json.php",
{entry : 'carlo' ,
type:'first_name',
mySecretCode : 'e8a53543fab6f00ebec85c535e'
}).then(function(response){
users = response;
return users;
});
}
}
})
but when I call it from the controller with var user = userService.getUsers(); returns the below in the console:
user is [object Object]
and inspecting element within chrome I only see:
user is Promise {$$state: Object}
Also in chrome when I drill down on Promise the data value = "".
Can anyone take a look at my services and see if I'm doing anything wrong.
Thanks
.then returns a promise. You're falling for the explicit promise construction antipattern.
getUsers: function(){
return $http.post("https://url_json.php",
{entry : 'carlo' ,
type:'first_name',
mySecretCode : 'e8a53543fab6f00ebec85c535e'
})
}
The above is all you need. Then, in your controller:
userService.getUsers()
.then(function(response) {
$scope.data = response.data; // or whatever
});
I would recommend looking at John Papa AngularJS style guide. He has a lot of information about fetching service data, using it in controllers, etc.
In your controller you will have to assign the user variable by resolving the promise return from the getUsers like below:
$scope.user = [];
$scope.error ="";
userService.getUsers().then(function(data){
$scope.user = data
},function(err){
$scope.error = err;
});
Hope this helps.
Related
I using angularjs1 in ionic-1 application and Firebase Database.
And I am trying to post a string to the database using firebase REST API.
I want the data to be in the following format:
Firebase generated Key: "My string"
But what I actually get is :
Can anyone help me to know how to send the data in http post function as a string ?
Here is my code:
.service('postFollowedUser', ['$http', '$q','baseURL', function($http, $q,baseURL){
var deferObject,
myMethods = {
postUser: function(uid,followedUid) {
var myPromise = $http({
method:'POST',
url: baseURL+'users/'+uid+'/followedUsers.json',
data:{followedUid}
}),
deferObject = deferObject || $q.defer();
myPromise.then(
// OnSuccess function
function(answer){
// This code will only run if we have a successful promise.
//alert('answer in servics'+JSON.stringify( answer));
deferObject.resolve(answer);
},
// OnFailure function
function(reason){
// This code will only run if we have a failed promise.
//alert(JSON.stringify( reason));
deferObject.reject(reason);
});
return deferObject.promise;
}
};
return myMethods;
}])
I tried to removing the curly braces but I got the following error:
"Invalid data; couldn't parse JSON object, array, or value."
Not sure if this is supported by firebase, but you are sending payload with object (data:{followedUid} is the same as data:{followedUid: followedUid}).
Try removing the curly braces:
$http({
method:'POST',
url: baseURL+'users/'+uid+'/followedUsers.json',
data: JSON.stringify(followedUid) // payload will be just the value of `followedUid`
})
Btw I am not sure what dark magic are you trying to do with the deferObject :] You can simply return the $http call, its return value is already a promise. You can still call then on it to process the results:
return $http.post(baseURL + 'users/' + uid + '/followedUsers.json', JSON.stringify(followedUid))
.then(function(answer) {
console.log(answer);
// return the answer so you can work with it later (again via `then`)
return answer;
}, function(error) {
console.log(error);
// throw the error so you can catch it later (possibly via `catch`)
throw error;
});
I have a problem with angular-ui typeahead component. It does not show values populated by angular resources, however using $http works well. I suppose I missing some trick here with asycn call and correct population of returned values.
Working code
$scope.searchForContact = function(val) {
return $http.get('/api/contacts/search', {
params: {
q: val
}
}).then(function(response){
return response.data.map(function(item){
return item.name;
});
});
};
Not working code
$scope.searchForContact = function(val) {
return Contact.search({q: val}, function(response){
return response.map(function(item){
return item.name;
});
});
});
...
'use strict';
app.factory("Contact", function($resource, $http) {
var resource = $resource("/api/contacts/:id", { id: "#_id" },
{
'create': { method: 'POST' },
'index': { method: 'GET', isArray: true },
'search': { method: 'GET', isArray: true, url: '/api/contacts/search', params: true },
'show': { method: 'GET', isArray: false },
'update': { method: 'PUT' },
'destroy': { method: 'DELETE' }
}
);
return resource;
});
Pug template code
input.form-control(
type='text'
ng-model='asyncSelected'
uib-typeahead='contact for contact in searchForContact($viewValue)'
typeahead-loading='loadingLocations'
typeahead-no-results='noResults'
)
i.glyphicon.glyphicon-refresh(ng-show='loadingLocations')
div(ng-show='noResults')
i.glyphicon.glyphicon-remove
|
|No Results Found
Angular resources are working fine, including search endpoint - I just output on page result returned by the search endpoint. In both results should be just an array with string values. What am I doing wrong?
The difference between $http.get and your Contact.search is that the first one returns a promise and the latter doesn't. Any $resource method will usually be resolved to the actual response. I'll show that with an example.
Getting data with $http
var httpResult = $http.get('http://some.url/someResource').then(function(response) {
return response.map(function(item) { return item.name });
});
The httpResult object contains a promise, so we need to use then method to get the actual data. Moreover, the promise will be resolved to the mapped array, which is the expected result.
Getting data with $resource
var someResource = $resource('http://some.url/someResource');
var resourceResult = someResource.query(function(response) {
return response.map(function(item) { return item.name });
});
The resourceResult isn't a promise here. It's a $resource object which will contain the actual data after the response comes from the server (in short, resourceResult will be the array of contacts - the original, not mapped, even though there is a map function). However, the $resource object contains a $promise property which is a promise similar to one returned by $http.get. It might be useful in this case.
Solution
I read in documentation that in order to make uib-typehead work properly, the $scope.searchForContact needs to return a promise. Instead of passing the callback function to search, I would simply chain it with the $promise from $resource object to make it work.
$scope.searchForContact = function(val) {
return Contact.search({q: val}).$promise.then(function(response){
return response.map(function(item){
return item.name;
});
});
});
Let me know if it works for you.
I thought I was doing well with AngularJS & REST until I came across a problem where my data service was not returning data back in time for my model to use it.
So, I have looked at and implemented a promise, but it is still not delaying until the HTTP REST call is done.
I would appreciate any help from the enlightened.
My routing passes a booking Id to the bookingController, which retrieves the booking details and then displays them in an editable form in booking.html template.
testLabApp.controller('bookingController', function ($q, $scope, $location, $window, $routeParams, service) {
if ($routeParams.id) {
$scope.bId = $routeParams.id;
//Expected this to setup my promise
var bookdefer = $q.defer();
bookdefer.promise
.then(function (booking) {
//When successful the result is assigned to my booking in the controller $scope
$scope.booking = booking;
//I am making a copy for form updates
$scope.editableBooking = angular.copy($scope.booking);
//When it runs console displays error:-
// "TypeError: Unable to get property 'Storeno' of undefined or null reference"
console.log("[bookingCtrl] 1 New: " + $scope.booking.Storeno + " and Editable: " + $scope.editableBooking.Storeno);
});
// Is this not calling my getBooking service function with the Id passed into my controller?
bookdefer.resolve(service.getBooking($scope.bookingId));
}
else {
//...
}
When code get to '[bookingCtrl] 1...' the console displays an error "TypeError: Unable to get property 'Storeno' of undefined or null reference", which makes me think that the booking data hasn't been retrieved.
then after this message the console displays:
[getBooking] Done = Id: 209 | Store no: 9180 | Description: test | Status: Booked
My data service includes a number of functions which make REST calls:-
testLabApp.factory('service', ['$rootScope', '$http', function ($rootScope, $http) {
var service = {};
$http({
method: 'GET',
url: "/_api/web/lists/GetByTitle('Bookings')/Items?$filter=Id eq '" + bookingId + "'",
headers: {
'Accept': 'application/json; odata=verbose'
},
}).success(function (d) {
var e = d.d.results[0];
booking = {
Id: e['Id'],
Storeno: e['Title'],
BookedBy: e['BookedBy'],
Description: e['Description'],
StartDate: e['StartDate'],
EndDate: e['EndDate'],
Status: e['Status']
};
console.log("[getBooking] Done = Id: " + booking.Id + " | Store no: " + booking.Storeno + " | Description: " + booking.Description + " | Status: " + booking.Status);
return booking;
}).error(function (er) {
console.log("[getBooking] http error : " + er);
});
};
Thanks again for any helps or suggestions.
Regards
Craig
The success function in your service is executed asynchronously. As a consequence, your service actually returns null to your controller. Here's what I've done in all my angular projects:
service.getStuff = function(id) {
var dfd = $q.defer();
$http({
method: 'GET',
url: '/api/some-end-point/id'
}).then(function(data) {
var result = data.data;
dfd.resolve(result);
}, function(error) {
$log.error(error);
dfd.reject(error);
});
return dfd.promise;
}
And my controllers are written like this:
if ($routeParams.id) {
$scope.bId = $routeParams.id;
//Expected this to setup my promise
service.getStuff($routeParams.id).then(
function(data){
$scope.booking = data;
},
function(error){
console.log(error);
}
);
}
'Below is an example of an asynchronous get call from a controller using a service. You can actually return $http.get() to your controller in order to not need to create a new deferred object:
(function(){
angular.module('app', []);
angular.module('app').factory('service', ['$http', function($http){
return {
getData: getData;
}
function getData(){
return $http.get('/url')
.success(function(data){
//Do business logic here
return data;
})
.error(function(error){
return error;
});
}
}]);
angular.module('app').controller('controller', ['$scope', 'service', function($scope, service){
service.getData()
.success(function(data){
$scope.data = data;
})
.error(function(error){
//error logic
});
}]);
})();
I'm trying to call a list of articles from the NPR API. I have a working URL which returns as JSON. However, somewhere in my controller, I'm getting lost getting the object. When I console.log it to test, it returns as [object Object] and nothing else. My service looks like this:
app.factory('nprService', function($resource) {
//call npr api
return $resource('http://api.npr.org/queryid=61&fields=title,byline,text,image,all&output=JSON...
and my controller:
app.controller('ArticleListCtrl', function($scope, nprService) {
//call the service and store as a variable
$scope.article = nprService.get();
});
I've tried using query to get the result, like this, but it's returning a single JSON object so that obviously didn't work.
//call the service and store as a variable
nprService.query(function(data) {
$scope.article = data;
});
Any help would be greatly appreciated. Thanks in advance.
You need to use a promise construct to get at the data. The controller code can be re-written as:
app.controller('ArticleListCtrl', function($scope, nprService) {
//call the service and store as a variable
nprService.get().then(function(result){
$scope.article = result.data;
});
The $resource.get() function returns a promise. It should be used this way:
nprService.get().success(function(data, status, headers, config){
$scope.article = data;
}).error(function(data, status, headers, config){
console.log(status);
});
Using Angular 6 you can try this
myFunctionName(){
this.http.get(`http://www.thesoftdesign.com`)
.map(res => res.json())
.subscribe(data => {
this.data = data;
console.log('data', this.data);
});
}
I'am not pro in Angular and am still lerning. Hope I get some help here.
I want to build an App with different views. I need to detect the browser and also fetch some data from a server. For this I created a service, where I do this work.
My desire is to use the data of the service all views. How is proper way to store and cache the data so that I can use it in all my Views/Controllers?
Here is what I got so far.
My Service:
.factory('DataService', function($http, $q, $timeout) {
var data = { };
return {
notes: function() {
// This exposed private data
return data;
},
addItem: function(itemname, itemvalue) {
// This is a public function that modifies private data
data[itemname] = itemvalue;
}
getPlatform: function() {
var getPlatformData = function() {
var deferred = $q.defer();
BrowserDetect.init();
deferred.resolve(BrowserDetect.OS);
return deferred.promise;
};
return {
getPlatformData: getPlatformData
};
},
getServerData: function() {
//if(!data.getServerData){
var getData = function() {
var deferred = $q.defer();
$http({
url: 'js/fakeGet.json',
method: 'get',
dataType: 'json',
}).success(function(data) {
data.scanResponse = data;
deferred.resolve(data);
})
return deferred.promise;
};
return {
getData: getData
};
//}
// return data.scanResponse;
}
};
});
My controller:
DataService.getPlatform().getPlatformData().then(function(platform) {
console.log('Another browserDetect request');
$scope.platform = platform;
DataService.addItem("platform", $scope.userPlatform);
});
First of all, as nordyke mentioned in his answer, you'd better split the service to smaller ones.
Second, you're asking for how to caching the data, and since you're using promise, $q.when() is what you need. I will take the getPlatform as an example to get you started:
.factory('DataService', function($http, $q, $timeout) {
var os; // this variable is used to store the result
return {
getPlatform: function() {
var getPlatformData = function() {
if (!os) { // no previous data available, look into other service to fetch the data
var deferred = $q.defer();
BrowserDetect.init();
os = BrowserDetect.OS; // store data
deferred.resolve(os);
return deferred.promise;
}
return $q.when(os); // there is previous data, return it as promise
};
return {
getPlatformData: getPlatformData
};
}
};
});
In this way, OS information is cached, and
DataService.getPlatform().getPlatformData().then(function(platform) {
...
});
will only fetch the platform information once during the life-time of the DataService. You can apply the same idea to getServerData as well to cache the data from the server.
Caching your data in a service singleton is a good approach, and I like your straightforward implementation of it. My only recommendation would be to split up your 3 concerns into separate services.
Browser Detection
Server Requests (which will be split up even more once you have more requests.)
Data Caching