I'm trying to save the return value of $http service inside my controller, but I get "undefined" like response
In my controller, I call a service that uses the $http:
//this returns undefined
vm.user_instruments = instruments.getInstruments();
My service:
function instruments($http){
this.getInstruments = function(){
$http.get('url/').
then(function(response) {
/*this console.log print the response,
but this value I can't get it in my controller*/
console.log(response.data);
return response.data;
}, function(error) {
return error.data;
});
}
}//end service
So, what am I doing wrong? My purpose is that the controller be ignorant of any details of HTTP
Several problems . First your service function isn't returning anything .... return $http from it.
this.getInstruments = function(){
// return the request promise
return $http.get('url/').
then(function(response) {
return response.data;
}, function(error) {
return error.data;
});
}
Then in controller assign the scope inside a promise callback:
instruments.getInstruments().then(function(data){
vm.user_instruments = data
});
you have two options to do this:
1. return the promise to the controller and use the promise in the controller
function service ($http) {
this.request = function () {
return $http.request({ /*...*/ });
};
}
function controller (service) {
service.request().then(function (resp) {
console.log(resp);
});
}
2. send callback to service and return the data to the callback
function service ($http) {
this.request = function (callback) {
return $http.request({ /*...*/ }).then(function (resp) {
callback(null, resp);
}, function (err) {
callback(err);
});
};
}
function controller (service) {
service.request(function (err, resp) {
if (err) return console.log(err);
console.log(resp);
});
}
the popular option is to use promises, so use option 1 :)
Try this way
Service:
function instruments($http){
this.get = function(callback){
$http.get('/url').success(function(res){
callback(res);
});
}
} /* end service */
Controller:
instruments.get(function(res){
vm.instruments = res;
});
It should work.
PS: typed in mobile.
Related
I am looking to assign as an object a Fetch API promise from a local GeoJSON file.
Here is the code
fetch("data/sites.geojson")
.then(function(response) {
return response.json();
})
.then(function(data) {
L.geoJSON(data, {
pointToLayer: styles_sites
}).addTo(map);
});
};
I tried the call back method, as advised here
Saving fetched JSON into variable
(EDIT) New code, but there is still a missing formal parameter
function getData("data/sites.geojson", cb) {
fetch("data/sites.geojson")
.then(function(response) {
return response.json();
})
.then(function(data) {
L.geoJSON(data, {
pointToLayer: styles_sites,
onEachFeature: function (feature, layer) {
layer.on('mouseover', function() {
layer.openPopup(layer.bindPopup("<b>"+feature.properties.nombre+"</b>"))
});
layer.on('mouseout', function() {
layer.closePopup();
});
layer.on('click', function () {
layer.bindPopup("<b>Nombre: </b>"+feature.properties.nombre+"<br><b>Barrio: </b>"+feature.properties.barrio+"<br><b>Tipo: </b>"+feature.properties.tipo+"<br><b>Ubicacion: </b>"+feature.properties.ubicacion+"<br><b>Correo: </b>"+feature.properties.contacto);
});
}
}).addTo(map);
.then(function(result) {
cb(result);
});
});
};
getData("data/sites.geojson", function (data) {
return console.log({data});
});
Most probably just incorrect syntax of your callback function:
// Use either arrow function
getData("data/sites.geojson", (data) => {
return console.log({data});
});
// or standard function
getData("data/sites.geojson", function (data) {
return console.log({data});
});
I found the way to work this out by adding within the fetch function, what I originally wanted to do on the map.
This was to add a L.controlLayer using the geojson as overlay.
This is the code that made it work:
let sites = getData()
.then((function(data) {
L.geoJSON(data, {
pointToLayer: styles_sites,
onEachFeature: function LayerControl(feature, layer) {
var popupText = "<b>" + feature.properties.nombre + "<br>";
layer.bindPopup(popupText);
category = feature.properties.tipo;
// Initialize the category array if not already set.
if (typeof categories[category] === "undefined") {
categories[category] = L.layerGroup().addTo(map);
layersControl.addOverlay(categories[category], category);
}
categories[category].addLayer(layer);
layer.on('mouseover', function() {
layer.openPopup(layer.bindPopup("<b>"+feature.properties.nombre+"</b>"))
});
layer.on('mouseout', function() {
layer.closePopup();
});
layer.on('click', function () {
layer.bindPopup("<b>Nombre: </b>"+feature.properties.nombre+"<br><b>Barrio: </b>"+feature.properties.barrio+"<br><b>Tipo: </b>"+feature.properties.tipo+"<br><b>Ubicacion: </b>"+feature.properties.ubicacion+"<br><b>Correo: </b>"+feature.properties.contacto);
});
}
}).addTo(map);
}));
Actually it comes from one of your answer on another post ghybs.
I am learning React and I am trying to display a list of users from and ajax call. I am getting an unexpected token error from CodePen when I add the line
export default Users;
When I remove the line there are no more errors but the list of users is not being displayed.
My code:
function GetUsers(project){
$.ajax({
url: "https://jsonplaceholder.typicode.com/users",
success: function (data) {
console.log(data);
callback(null, data);
},
error: function (error) {
console.log(data);
callback(error, {});
}
});
}
function UserList(users) {
const userItems = users.map((user) =>
<ul>
<li>
{ user.name }
</li>
<li>
{ user.email }
</li>
<li>
{ user.phone}
</li>
</ul>
);
return (userItems);
}
class Users extends Component {
componentDidMount() {
GetUsers(null, function (err, data) {
if (err)
{
console.log(err);
}// do something
this.setState({ users: data })
}.bind(this))
}
render() {
return(
<UserList user = {this.state.users} />
);
}
}
if (document.getElementById('root')) {
ReactDOM.render(<Users />, document.getElementById('root'));
}
Here is my code.
Thank you for any and all help!
Problem 1 in AJAX call
function GetUsers(project){
$.ajax({
url: "https://jsonplaceholder.typicode.com/users",
success: function (data) {
console.log(data);
callback(null, data);
},
error: function (error) {
console.log(data);
callback(error, {});
}
});
}
$.ajax is asynchronous call, that means it doesn't returns directly any value (how it could if it is fetching the results from the internet) it Just creates another function which will call success and error when completed.
That's why we need to wrap it with callbacks
function GetUsers(project, resolve = () => {}, reject = () => {}) {
}
Problem 2 in mount
componentDidMount() {
GetUsers(null, function (err, data) {
if (err)
{
console.log(err);
}// do something
this.setState({ users: data })
}.bind(this))
}
This code is completely wrong, it has even syntax error so not worth to discuss it in details.
We need to call our new function and pass success callback for mutating the state
GetUsers(null, users => {
this.setState({ users });
});
In this way we will call GetUsers wait for it's results and only after that we will mutate the state with new result
3 problem in component creation
React component's don't have state by default, you need to infer the state from constructor so we need to change initialization to
constructor(props) {
super(props);
this.state = {
users: false
};
}
otherwise you will get Cannot call setState of undefined as state is not automatically created for performance purposes and all components are Pure by default.
I have created a working sandbox here
in
function GetUsers(project){
$.ajax({
url: "https://jsonplaceholder.typicode.com/users",
success: function (data) {
return data;
},
error: function (error) {
console.log(error);
return {};
}
});
}
--
success: function (data) {
return data;
}
doesn't do what you think it does. return data isn't really returning the data... anywhere.
You need to have a callback.
function GetUsers(project, callback){
$.ajax({
url: "https://jsonplaceholder.typicode.com/users",
success: function (data) {
callback(null, data)
},
error: function (error) {
callback(error, {})
}
});
}
class Users extends Component {
componentDidMount() {
GetUsers(null, function (err, data) {
if (err) // do something
this.setState({ users: data })
}.bind(this))
}
render() {
return(
<UserList user = {this.state.users} />
);
}
}
you can also Promise-ify things to simplify the logic
First, this is my service that retrieves a promise for an API key:
app.factory('AuthenticationService', function($http) {
return {
getData: function() {
return $http.get('http://game.mywebsite.com/start/?token=2132')
.then(function(result) {
return result.data;
}
);
}
}
In my controller I bind the key:
AuthenticationService.getData()
.then(function(result) {
$scope.apiKey = result;
});
I was wondering where to pass an API key which I retrieved from the server. I have a controller implementation:
DrawService.getData($scope.apiKey)
.then(function(result) {
$scope.numbers = result.data;
});
And the service:
app.factory('DrawService', function($http) {
return {
getData: function(apiKey) {
return $http.get('http://game.mywebsite.com/draw/')
.then(function(result) {
return result.data;
});
}
}
And still I am not authorized to access data from the server. I was wondering where to pass this apiKey parameter in order to be authorized, considering I have more services which should return some data, but require authorization first?
bltzrrr, is game.mywebsite an application of yours?
If so, you need to know the param name in order to request it right.
Supposing it is apiKey, it'd look like:
$http.get('http://game.mywebsite.com/draw/', {params: {apiKey: 'apiKey'}});
Hope this is going to help you
its depends on what kind of authorization your server had implemented
Looking at your code i believe you need to pass api token in service headers in order to access data.
you can pass data in to the header of each service
app.factory('DrawService', function($http) {
return {
getData: function(apiKey) {
return $http.get('http://game.mywebsite.com/draw/',{
headers: { "Authorization": "Bearer APIKEY"}
}).then(function(result) {
return result.data;
});
}
}
Or you can set it globally into header for each and every service call
app.factory('DrawService', function($http) {
return {
getData: function(apiKey) {
$http.defaults.headers.common.Authorization = "Bearer APIKEY";
return $http.get('http://game.mywebsite.com/draw/')
.then(function(result) {
return result.data;
});
}
}
Authorization can be bearer,basic or digest.
Iam build single page app in AngularJs,and I need call Facebook UI dialog.And if user click 'ok',or 'cancel',successReport methos not call immediately.This method call after i click on any button in page,or link.Similar to internal queue
service.showStreamDialog=function (json) {
if (json.stream) {
var newCardSentId = json.cardSentId;
FB.ui(json.stream, function (resp) {
if (resp && resp.post_id) {
reportService.successReport(newCardSentId,newCardSentId,resp.post_id);
} else {
reportService.cancelReport(newCardSentId);
}
});
}
};
// in other file
var successReport=function(cardId,cardSentId,postId){
var defered = $q.defer();
$http.post(reportUrl,$.param({
cardId:cardId,
cardSentId:cardSentId,
postId:postId,
accessToken: ACCESS_TOKEN
}))
.success(function(data){
defered.resolve(data);})
.error(function(data){
defered.reject(data);
});
return defered.promise;
};
I found problem. It was in integration facebook api in my app.I add $rootScope.$apply call,
and all working as i expected
service.showStreamDialog = function (json) {
if (json.stream) {
var newCardSentId = json.cardSentId;
FB.ui(json.stream, function (resp) {
if (resp && resp.post_id) {
$rootScope.$apply(function () {
$rootScope.$broadcast('CARD_SENT_SUCCESS', {cardSentId: newCardSentId,post_id:resp.post_id});
});
} else {
$rootScope.$apply(function () {
$rootScope.$broadcast('CARD_SENT_CANCEL', {cardSentId: newCardSentId});
});
}
});
}
};
I have a controller and factory defined as below.
myApp.controller('ListController',
function($scope, ListFactory) {
$scope.posts = ListFactory.get();
console.log($scope.posts);
});
myApp.factory('ListFactory', function($http) {
return {
get: function() {
$http.get('http://example.com/list').then(function(response) {
if (response.data.error) {
return null;
}
else {
console.log(response.data);
return response.data;
}
});
}
};
});
What confuses me is that I get the output undefined from my controller, and then the next line of console output is my list of objects from my factory. I have also tried changing my controller to
myApp.controller('ListController',
function($scope, ListFactory) {
ListFactory.get().then(function(data) {
$scope.posts = data;
});
console.log($scope.posts);
});
But I receive the error
TypeError: Cannot call method 'then' of undefined
Note: I found this information on using a factory through http://www.benlesh.com/2013/02/angularjs-creating-service-with-http.html
You need to either use a callback function or just put a return before $http.get...
return $http.get('http://example.com/list').then(function (response) {
if (response.data.error) {
return null;
} else {
console.log(response.data);
return response.data;
}
});
$http.get is asynchronous so at the time you try to access it (inside your controller) it may not have data (hence you get undefined).
To solve this I use .then() after I call the factory method from my controller. Your factory then would look something like:
myApp.factory('ListFactory', function($http) {
return {
get: function() {
$http.get('http://example.com/list');
}
};
});
And your controller:
myApp.controller('ListController', function($scope, ListFactory) {
ListFactory.get().then(function(response){
$scope.posts = response.data;
});
// You can chain other events if required
});
Hope it helps