Access $scope.variable from $scope.function - angularjs

In this code my console.log logs undefined. I am trying to access $scope property from other $scope method. How to do this properly?
AppControllers.controller('DepartureLocationCtrl', [
'$scope','$http',
function($scope,$http){
$http.get('/airports').success(function(data){
$scope.departureLocations = data;
});
$scope.showSuggestions = function(){
console.log($scope.departureLocations);
}
$scope.showSuggestions()
}]);

Your code tries to log the value of $scope.departureLocations immediately after you have sent the http request to get them from the backend. At this time, the http response has not come back yet, and the $scope.departureLocations = data; line has not been executed yet.
The first A in AJAX means Asynchronous.
Move $scope.showSuggestions() inside the function passed to success(). And BTW, use then() instead of success(): success() is deprecated.
AppControllers.controller('DepartureLocationCtrl', [
'$scope','$http',
function($scope,$http){
$http.get('/airports').then(function(response){
$scope.departureLocations = response.data;
$scope.showSuggestions()
});
$scope.showSuggestions = function(){
console.log($scope.departureLocations);
}
}]);

Related

Using the service data in the controller

I have placed the service and the controller in the same js file. So Im trying to fetch the data from the service and use it in my html. In my code Im able to generate the data from the service but not able to assign it to a $scope in the controller and use it in the html. So how do I get the data and assign it to the $scope so that I can use it in my html.
var app = angular.module("app",[]);
app.factory('factoryServices',function($http){
var newObject = {};
var _getChart= function(){
$http.get("http://citibikenyc.com/stations/json")
.success(function(data, status){
if(data) {
return data;
}
}).error(function(data,status){
return error;
});
}
newObject.getChart = _getChart;
return newObject;
});
app.controller("chartController",function($scope,$http,factoryServices){
factoryServices.getChart($scope.chartServicesCompleted);
$scope.chartServicesCompleted = function(data){
$scope.serviceResponse = data;
}
})
If you rewrite your code like this, it should work as expected:
var app = angular.module("app",[]);
app.factory('factoryServices',function($http){
var newObject = {};
var _getChart= function(){
return $http.get("http://citibikenyc.com/stations/json")
.then(function(response){
if(response.data) {
return response.data;
}
}, function(response){
console.error("getChart failed with ",response);
});
}
newObject.getChart = _getChart;
return newObject;
});
and your controller
app.controller("chartController",function($scope,$http,factoryServices){
factoryServices.getChart().then(chartServicesCompleted);
function chartServicesCompleted(data){
$scope.serviceResponse = data;
}
})
The reason your initial code doesn't work, is because your getChart doesn't actually take an argument. So passing your callback like this: getChart($scope.chartServicesCompleted) doesn't do anything. In the rewritten code, I've made it so the getChart function returns the promise created by $http.get(..) which then allows you to use .then([callback]) in your controller.
you are passing a callback function but not handling inside the service method.
do change as
var _getChart= function(callback){
$http.get("http://citibikenyc.com/stations/json")
.success(function(data, status){
callback(data);
}).error(function(data,status){
callback(data);
});
}
now factoryServices.getChart($scope.chartServicesCompleted); will work
you can make more generic by handling success and error callback separately.
or one more way is to implement the success and error logic inside your controller.
but do not forget to check the function type i.e
if(typeof callback == 'function'){
callback(data);
}
Edit: as per advanced you call implement promises.
if you are using angular version 1.6, the success and error methods have been depreciated.
secondly you can do inside service return the http object
var _getChart= function(){
return $http.get("http://citibikenyc.com/stations/json");
}
and then handle the promise in the controller like
factoryServices.getChart().then(successMethod, error method);
Let the service return the promise to the controller. ex:
var _getChart= function(){
return $http.get("http://citibikenyc.com/stations/json");
}
and in the controller handle the promise. Use 'then' instead
factoryServices.getChart().then(function(response){var theDate = response.data},function(error){});
you can declare methods instead in the controller for handling the success and error
factoryServices.getChart).then(onSuccess,onError);
Don use the .success method and .error method. They dont't behave as other promises. So get used to 'then'
You really don't need to handle errors in the service method.I use angular interceptors in most of the cases. Check em out. But sometimes you need to handle the error in the controller. So its good to get the callback in the controller

Code runs in a different order than expected

JS
<script type="application/javascript">
var app = angular.module("app", []);
app.controller("AppCtrl", function ($scope, $http) {
$scope.data = [];
$http.get("{{ url_for('data') }}")
.then(function (result) {
$scope.data = result.data;
console.log(result.data); //first
});
console.log($scope.data); //second
...
</script>
first console.log returns the correct data (Array with one item), the second one returns empty Array.
Notice that the order of execution is not as the code:
Console
Array [ ]
Array [ "data" ]
Why the second console.log executes before the first one, How can it be fixed?
Because the http.get is asynchronous i.e. it goes off and does something on another thread, whilst the rest of the program continues. By the time it's finished, and done it's console.log, the '2nd' console.log has already run.
The call to $http.get is asynchronous so you don't know up-front how long it will take. console.log($scope.data) will be executed immediately following the $http.get request because the request will still be processing and waiting to return.
If you want to execute logic after your requests complete, you can add additional logic inside of the your then() and then chain them if you require additional requests to be executed. For instance,
$http
.get("{{ url_for('data') }}")
.then(function (result) {
$scope.data = result.data;
// do more things
return $http.get('foo/bar')
}).then(function (fooBar) {
// $scope.foo = bar;
});
All $http calls return a promise so you're able to leverage the $q service to facilitate any promise specific functionality.
Angular's $http methods run asynchronously. This means the console.log($scope.data); will be excecuted first and the console.log(result.data) inside then will be excecuted when the promise from $http resolves.
$http is the service which will be performed asynchronously
This is because Angular's JavaScript runs asynchronously. This means that It will keep running even though it's waiting on another task. You should look up angular's guild on Promises.

Angularjs scope length outside function

Im a newbie in AngularJs and do not really know how to get length of response outside function.
var onUsers = function(response){
$scope.users = response.data;
console.log($scope.users.length); //here works
}
But when i try outside onUsers function
console.log($scope.users.length);
I get an error.
I think the problem is that you are trying to access $scope.users.length before your response has returned from the server. so $scope.users is still undefined. This is a classic problem of asynchronous javascript and you need to use promises for this.
Which means that you should write the code that you are executing outside onUsers in the promise callback.
Read this: https://docs.angularjs.org/api/ng/service/$q
You can use $scope.$watch for run a function when the variable change.
$scope.$watch('users', function(users) {
console.log(users.length);
});
AS the angular code runs asynchronous so console.log($scope.users.length) runs before the promise returned.
var onUsers = function(response){
$scope.users = response.data;
console.log($scope.users.length); //here works
}
your console.log($scope.users.length) in above function works because it is a success handler.
you can get the your console.log works out side the success handler by using $timeout. i am assuming after 5000 your response will arive.
$timeout(function() {
console.log($scope.users.length);
}, 5000);

How can I create a service that returns the value promise

I want to create a service that returns a json
Or by request to to the server, or by checking if it exists already in: Window.content
But I don't want to get a promise from my Controller !
I want to get the json ready !
I have tried several times in several ways
I tried to use with then method to do the test in my Service
but I still get a promise
( Whether with $http only, and whether with $q )
I could not get the value without getting promise from my Controller
My Service :
app.service('getContent',['$http', function( $http ){
return function(url){ // Getting utl
if(window.content){ // if it's the first loading, then there is a content here
var temp = window.content;
window.content = undefined;
return temp;
}
return $http.get(url);
};
}]);
My Controller:
.state('pages', {
url: '/:page',
templateProvider:['$templateRequest',
function($templateRequest){
return $templateRequest(BASE_URL + 'assets/angularTemplates/pages.html');
}],
controller: function($scope, $stateParams, getContent){
// Here I want to to get a json ready :
$scope.contentPage = getContent(BASE_URL + $stateParams.page + '?angular=pageName');
}
});
If the data exists, just resolve it in a promise.
While this process is still asynchronous it won't require a network call and returns quickly.
app.service('getContent',['$http', '$q', function( $http, $q ){
return function(url){
// create a deferred
var deferred = $q.defer();
if(window.content){ // if it's the first loading, then there is a content here
var temp = window.content;
window.content = undefined;
deferred.resolve(temp); // resolve the data
return deferred.promise; // return a promise
}
// if not, make a network call
return $http.get(url);
};
}]);
Just to reiterate, this asynchronous, but it won't require a network call.
This is not possible. If the code responsible to calculate or retrieve the value relies on a promise, you will not be able to return the value extracted from the promise by your function.
Explanation: This can easily be seen from the control flow. A promise is evaluated asynchronously. It may take several seconds to retrieve json from a server, but the caller of your function should not wait so long because your whole runtime environment would block. This is why you use promises in the first place. Promises are just a nice way to organize callbacks. So when your promise returns, the event that caused the function call will have already terminated. In fact it must have, otherwise your promise could not be evaluated.
You're thinking about this wrong. A service always returns a promise, because there is no synchronous way of getting JSON from an API:
app.factory('myService', ['$http', function($http) {
return $http('http://my_api.com/json', function(resp) {
return resp.data;
});
}]);
You would then call this within your controller like so:
app.controller('myController', ['$scope', 'myService', function($scope, myService) {
myService.then(function(data) {
$scope.contentPage = data; // here is your JSON
}, function(error) {
// Handle errors
});
}]);
Your service is returning a promise as it's written at the moment. A promise is always a promise, because you don't really know when it will be finished. However with Angular's 2 way data binding this isn't an issue. See my edits bellow as well as the example on $HTTP in the docs
In your controller
controller: function($scope, $stateParams, getContent){
getContent(BASE_URL + $stateParams.page + '?angular=pageName')
.then(aSuccessFn, aFailedFn);
function aSuccessFn(response) {
// work with data object, if the need to be accessed in your template, set you scope in the aSuccessFn.
$scope.contentPage = response.data;
}
function aFailedFn(data) {
// foo bar error handling.
}
}

angular using $http in factory

I seem to be having an issue sending json from my factory out to controllers
Here is my factory
.factory("UserService", function($http) {
var LevelsHere;
$http.get("/assets/images/generated.json").success(function(data){
LevelsHere = data;
return LevelsHere;
});
return {
all: function() {
return LevelsHere;
},
first: function() {
return LevelsHere[0];
}
};
})
I am simply trying to send the json object out (or bits of it) with this factory. I can console.log inside the http get and it seems to be grabbing the json just fine. I seem to have hit a wall, any help would be much appreciated. I would just like the all ad first functions to be working. thanks!
I first had success by hard coding the levelsHere above it with the json string like var levelsHere = [{"stuff in here"}], but when i moved it over to an $http it doesn't work.
Since you don't have any $watch to look over the value returned from asynchronous $http.get request, the updated value is not available to the consumer. As $http.get request returns a promise, you can leverage the promise and update the value on success of the promise in then() as below:
var app = angular.module('app', [])
.factory("UserService", function($http) {
var LevelsHere = $http.get("https://api.github.com/users/mralexgray/repos")
.success(function(data){
return data;
});
return {
all: function() {
return LevelsHere;
}
};
})
.controller('controller', function(UserService, $scope){
UserService.all().then(function(data){
$scope.value = data;
});
})
DEMO
What is not working exactly? My guess is that you got undefined immediately after this factory method, since $http uses deferred object
You are returning LevelsHere before the async call is finished. The order of your operation goes:
call http.get
return all and first which return LevelsHere (even though the http request has not finished)
http get returns json
success call back fires returning LevelsHere to nobody.
A better way is to just return the promise:
return $http.get("/assets/images/generated.json")
then in your controller you can get the value from the promise by calling the success function. If you try to resolve the promise in the factory and return the value, your controller will try to use the value before it's returned from the server.
var promise = UserService()
promise.success(function(data){
// do something with data
}

Resources