I am currently using Angular 1.3.14 and I would like to make an request using $http whenever a link is clicked. I am trying to place the $http request in a service so it's not bound to any one controller and can be accessed by multiple controllers. I've created two functions sayHello() and getData(). I want each one to console.log when clicked. Only the sayHello() function does, but not the getData() function.. Here's what I don't understand.
Why does the $http request fire on load, and not on click whereas the sayHello function works perfectly?
How can I modify my code so it works as intended?
<p>Console Log Our Data</p>
<p>
Console Log The Word "Hello"</p>
var app = angular.module('myApp', [])
.controller('mainCtrl', function($scope, dataService){
$scope.sayHello = dataService.sayHello;
$scope.getData = dataService.getData(function(response){
$scope.myData = response.data;
console.log($scope.myData);
});
})
.service('dataService', function($http){
this.getData = function(callback){
$http.get('http://jsonplaceholder.typicode.com/posts')
.then(callback);
}
this.sayHello = function(){
console.log("Hello!");
}
});
Codepen for reference http://codepen.io/benweiser/pen/remvvo/
That's because $scope.getData is equal to undefined when it should be a function
$scope.getData = function () {
dataService.getData(function(response) {
$scope.myData = response.data
console.log($scope.myData)
})
}
Update: You can send parameters either from the call to the method or from the method itself, suppose you have the following input
<input ng-model="name">
Then you can use the send the value and use it in your service as follows
<a ng-click="getData(name)">get data</a>
$scope.getData = function (name) {
dataService.getData(name)
.then(function (response) { ... })
}
Or using it directly in the controller
<a ng-click="getData()">get data</a>
$scope.getData = function () {
dataService.getData($scope.name)
.then(function (response) { ... })
}
Note that both assume that dataService.getData() returns a promise instead of passing the callback so you'd also need to do the following on your service if you want to code it like above
this.getData = function (name) {
// do something with name
return $http.get('http://jsonplaceholder.typicode.com/posts/' + name)
}
You should read more on Promises vs callbacks and how you can take advantage of them :)
When you do this
$scope.getData = dataService.getData(function(response){
$scope.myData = response.data;
console.log($scope.myData);
});
})
dataService.getData get executed immediately. As a result, $scope.getData is set to a promise instead of a function you intent to bind to ng-click
change this line $scope.getData = dataService.getData to the following which will actually set a function with callback to $scope.getData
$scope.getData = dataService.getData.bind(this, function(response) {
$scope.myData = response.data;
console.log($scope.myData);
});
I would try doing something like this. Should be easy to apply to your code above
//in your factory
app.factory('dataFactory',function($http){
factory = {};
//get data
factory.getData = function(obj){
return $http({
method: 'GET',
url: 'http://jsonplaceholder.typicode.com/postsn'
})
};
return factory
});
//in your controller
app.controller(someCtrl,function($scope,dataFactory){
dataFactory.getData().then(function(data){
console.log('This will be your data: ', data)
})
})
The Ajax query was being made when controller was first loading. Your bind with "getData" wasn't with a function, but with an ajax call, and that was why it was not triggered.
This refactor works on codepen:
'use strict';
var app = angular.module('myApp', [])
.controller('mainCtrl', function($scope, dataService){
$scope.sayHello = dataService.sayHello;
$scope.getData = function(){
dataService.getData().then(
function(response){
$scope.myData = response.data;
console.log($scope.myData);
}
);
}
})
.service('dataService', function($http){
this.getData = function(callback){
return $http.get('http://jsonplaceholder.typicode.com/posts');
}
this.sayHello = function(){
console.log("Hello!");
}
});
Main updates:
$scope.getData is binded to a function, not an Ajax call/promise
Promise is outside the service (better solutions are welcome :-) ).
dataService.getData is called as a function. (Did't work in other way).
Related
This question already has answers here:
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
How do I return the response from an asynchronous call?
(41 answers)
Closed 7 years ago.
I define a variable by the name tst in controller, and i give some value in a function by the name GetOrders, but when i get tst in another function GetTotalValueOfProducts it is undefined and does not have value,this is what i do:
<script>
app.controller('OrderController', function ($scope, $http) {
$scope.quantity = 1;
$scope.Orders = {};
var tst ;
GetOrders = function () {
$http.get('/Order/GetAllOrders').success(function (response) {
$scope.Orders = response;
//here i set tst, and tst has value, i checked it has value and it's not undefined
tst = response;
});
}
GetOrders();
GetTotalValueOfProducts = function () {
//but here 'tst' is undefined!!!
var p = tst;
}
GetTotalValueOfProducts();
});
</script>
What is the problem?
This is happening because js is asynchronous.
You are executing GetOrders() as it is making http request, which will take time but before that http request finishes you are calling GetTotalValueOfProducts which makes it undefined.
<script>
app.controller('OrderController', function ($scope, $http) {
$scope.quantity = 1;
$scope.Orders = {};
var tst ;
GetTotalValueOfProducts = function () {
//but here 'tst' is undefined!!!
var p = tst;
}
GetOrders = function () {
$http.get('/Order/GetAllOrders').success(function (response) {
$scope.Orders = response;
//here i set tst, and tst has value, i checked it has value and it's not undefined
tst = response;
GetTotalValueOfProducts();
});
}
GetOrders();
});
</script>
The above should give you expected result. Not sure when you want to call the function.
Hi There AngularJS is all async so GetTotalValueOfProducts(); is getting called before success callback return any value from http. You have to call your function once the callback is completed.
You can use $q of AngularJS to accomplish it. Here is the link $q
This is a classic JavaScript async problem. Your second function is executed before the promise in the first function is resolved.
You should call
GetTotalValueOfProducts();
in success callback of $http service. Change the code like this
<script>
app.controller('OrderController', function ($scope, $http) {
$scope.quantity = 1;
$scope.Orders = {};
GetOrders = function () {
$http.get('/Order/GetAllOrders').success(function (response) {
$scope.Orders = response;
GetTotalValueOfProducts(response)
});
}
GetOrders();
GetTotalValueOfProducts = function (tst) {
var p = tst;
}
});
</script>
Try attaching tst variable into your inner $scope object.
EDIT
It was sloppy not seeing that these function are async. You should fetch your results as:
Try attaching tst variable into your inner $scope object.
EDIT
It was sloppy not seeing that these function are async. You should fetch your results as.
app.controller('OrderController', function ($scope, $http) {
$scope.quantity = 1;
$scope.Orders = {};
$scope.tst;
GetOrders = function () {
$http.get('/Order/GetAllOrders').success(function (response) {
$scope.Orders = response;
$scope.tst = response;
GetTotalValueOfProducts();
});
}
GetOrders();
GetTotalValueOfProducts = function () {
//but here 'tst' is undefined!!!
var p = $scope.tst;
}
});
Or even try to use $q
In Angular I have a service to access the google contacts api, then store all my contacts into variable (StorageVar) to be analyzed by other functions in the service.
Should I call one of the analysis functions before getting the data from the API, I want to call the getAPI function then (as in .then()) run the analysis function. The issue is that I can't figure out how to access any of the functions from the .then() scope.
angular.module('API',[])
.factory('API', ['$rootScope', '$http','$q', function ($rootScope, $http, $q) {
var StorageVar = [];
return{
getAPI: function(){
//does async call, returns promise, stores data into StorageVar
}
Analyze: function(){
if(StorageVar.length==0){
//need to get the data first
this.getAPI().then(function(){
//Analyze()
debugger;
}
}
}
In my controller I would want to use my service like this:
angular.module('views.local', ['API'])
.controller('localctrl',['API',function(API){
API.Analze()
//Callable even if the getAPI function hasn't run, so the Analyze function will take care of that.
}])
Any assistance is appreciated.
Is this what you mean?
angular.module('API',[])
.factory('API', ['$rootScope', '$http','$q', function ($rootScope, $http, $q) {
var StorageVar = [];
return{
getAPI: function(){
//does async call, returns promise, stores data into StorageVar
}
Analyze: function(){
if(StorageVar.length==0){
//need to get the data first
var _this = this;
this.getAPI().then(function(){
//Analyze()
_this.Analyze();
debugger;
}
}
}
I have an app.run() block that:
uses an Angular service that uses a $http.get to get some values and sets them in the $rootScope
calls another Angular component that uses the values from the $http.get
The issue is that the code in the second step runs before the HTTP call has replied with the values in the first step. I don't want the code in the second step to call the service directly.
How can I force the second step to wait for the first step to complete?
service.js
function getSomeConfigs() {
var promise = $http.get('/blah');
$rootScope.promise = promise
.then(function () {
$rootScope.someVariable = data.someVariable;
});
}
helper.js
$rootScope.someVariable
is undefined
You must chain the two steps:
$http.get('restAddress')
.then(function(result) {
$scope.myResult = result.data;
})
.then(function() {
MyFunctionIndirectlyDependingOnPreviousResult();
});
You can even place the call to MyFunctionIndirectlyDependingOnPreviousResult() inside the first then() callback:
$http.get('restAddress')
.then(function(result) {
$scope.myResult = result.data;
MyFunctionIndirectlyDependingOnPreviousResult();
});
$HTTP service returns a promise.
So just set the return from your $http.get to a var and you can use the .then method.
e.g.
//Controller
....
//appSvc.get is a call to your .factory or .service that returns the promise
var inputUrl = "myUrl/REST/";
var promise = appSvc.get(inputUrl);
promise.then(function (data) {
//DO SOMETHING WITH Returned DATA
}
...
//SERVICE
'use strict';
module.exports = function (ngModule) {
ngModule.factory('appSvc', ['$http', function ($http) {
function epicUniverse (inputUrl) {
return $http.get(inputUrl);
}
return {
get:epicUniverse
};
}]);
};
My controller cannot pick up the data that processed from $http.get() in requirejs environment. Any idea how can I fix it?
UserFactory.js
define(['app'], function (app) {
app.module1.factory('UserFactory', ['$http', function($http) {
//your minsafe controller
var factory = {};
factory.getUsers = function(){
$http.get('api.php').success(function(data) {
// here the data from the api is assigned to a variable named users
return data; // [{"id":"1","name":"Big Kev","email":"bigkev#example.com"},{"id":"2","name":"Judy","email":"punk#example.net"},{"id":"3","name":"Suzy","email":"suzy#example.com"},{"id":"4","name":"Joey","email":"sheena#example.org"},{"id":"5","name":"DeeD","email":"deedee#example.net"}]
});
};
return factory;
}]);
});
view.js,
define(['app'], function (app) {
app.module1.controller('View1Ctrl', ['$scope','UserFactory', function($scope,userFactory) {
//your minsafe controller
$scope.message = "Message from View1Ctrl";
$scope.users = userFactory.getUsers();
console.log($scope.users); // undefined
}]);
});
as you can see, I get undefined for $scope.users. It seems that console.log($scope.users); is executed before $http.get('api.php') in the factory. How can I fix this then?
This has nothing to do with Require; it is a very common misconception about how asynchronous code runs (especially promises).
You see factory.getUsers() makes an asynchronous call. The response will be available at a later time and success will be called with the response data at that later time. On the other hand, $scope.users = userFactory.getUsers() is synchronous. It is almost guaranteed that the async call wll NOT have returned by the time the next statement runs. And even if it has returned, the callback will NOT have run because Javascript is single threaded in the browser.
Moreover you have another serious fault: the success callback is "procedural" in the sense that it receives the response and has to do something with it. Its return value is disregarded!
To use promises (or at least $http) correctly in this case, change factory.getUsers to return the $http promise:
factory.getUsers = function(){
return $http.get('api.php');
};
And change the controller to use the promise or the success/error callbacks:
// option (1) with promise
userFactory.getUsers().then(function(response) {
$scope.users = response.data;
});
// option (2) callback
userFactory.getUsers().success(function(data) {
$scope.users = data;
});
I am new to angularjs. I am trying to call a function in a factory but I am getting the below error,
Error: [$injector:undef] Provider 'todoStorage' must return a value from $get factory method.
This is my factory,
todomvc.factory('todoStorage', function ($q,$http) {
var STORAGE_ID = 'todos-angularjs-perf';
function get(){
var promise = $q.defer();
$http.get('http://localhost/test.php').success(function(data){
promise.resolve(data);
});
return promise.promise;
}
});
And this is how I call the function,
var todos = $scope.todos = todoStorage.get();
What exactly is happening and why this error coming up?
todomvc.factory('todoStorage', function ($q,$http) {
var STORAGE_ID = 'todos-angularjs-perf';
function get(){
return $http.get('http://localhost/test.php');
}
return{get:get};
});
//call the service like this
todoStorage.get().then(function(res){
$scope.todos = res.data;
});
Your code is not returning the actual service factory. Since you are using factory you have return some JavaScript object pointing to your internal function. Otherwise it's not a valid factory, and your external code will have no way of getting to the internal get function.