need angular response of post/get request out of scope, any suggestions? - javascript

i am trying to get response of post/get requests , getting response successfully inside post/get,but unable to get result out of post/get .
when i print on console it is showing "undefined". any suggestions , here is my code
index.html:
<div ng-app="myApp" ng-controller="customersCtrl">{{ponies}}</div>
Angular code:
var myApp = angular.module('myApp', []);
angular service:
myApp.factory('ponyService', function($http) {
var getPonies = function() {
return $http.get('https://www.w3schools.com/angular/customers.php');
};
return {
getPonies: getPonies
};
});
myApp.controller('customersCtrl', function($scope, ponyService) {
ponyService.getPonies().success(function(data) {
$scope.ponies = data;
});
console.log($scope.ponies); // here want to print data because want to use whole controller
});

That's because posts and gets are asynchronous.
Your console.log won't wait for the response.
Put your console inside success in order check it's data.
Try like this
ponyService.getPonies().success(function(data) {
$scope.ponies = data;
console.log($scope.ponies);
});
or you can watch it's changes (but it's not recommended just for test purposes),
Like this
ponyService.getPonies().success(function(data) {
$scope.ponies = data;
});
$scope.$watch("ponies",function(val){
if(val)
console.log(val)
})

It is because a $http returns a promise (async request) so if you did something like this
ponyService.getPonies().success(function(data) {
$scope.ponies = data;
});
console.log($scope.ponies);
it will log undefined, as you are trying to log it before the request is finished.So you need to chain to that promise in any code that needs to access the resolved data.Like:
ponyService.getPonies().success(function(data) {
$scope.ponies = data;
console.log($scope.ponies);
/* access data or $scope.ponies in here */
});
or you can use promise like
ponyService.getPonies().then(function (data) {
$scope.ponies = data;
console.log($scope.ponies);
/* access data or $scope.data in here */
});

Related

Handling JSONP response in Angular JS 1.6

how can i handle a jsonp response? i tried to search but i cant solve it. the screen shot below shows a jsonp result.1
i get that jsonp response using this code, services.js
var app=angular.module('F1FeederApp.services', []);
app.config(function($sceDelegateProvider) {
$sceDelegateProvider.resourceUrlWhitelist([
'self',
'http://ergast.com/**'
]);
});
app.factory('ergastAPIservice', function($http) {
var ergastAPI = {};
var urlFiltered = 'http://ergast.com/api/f1/current/driverStandings.json';
ergastAPI.getDrivers = function() {
return $http({
method: 'JSONP',
url: urlFiltered
});
}
return ergastAPI;
});
now, i access it using the code below and gives me result on the 1st picture.
angular.module('F1FeederApp.controllers', []).
controller('driversController', function($scope, ergastAPIservice) {
$scope.nameFilter = null;
$scope.driversList = [];
// //ergastAPIservice.getDrivers() ->> when i try this i get error this is not a function.
//ergastAPIservice.getDrivers().success(function (response) {
//Dig into the responde to get the relevant data
// $scope.driversList = response.MRData.StandingsTable.StandingsLists[0].DriverStandings;
//});
//code above doesnt work so i tried to access it or atleast show a value like
// the code below
console.log(ergastAPIservice.getDrivers());
console.log(ergastAPIservice.getDrivers().MRData.StandingsTable.StandingsLists[0].DriverStandings);
});
now i get the 1st picture using console.log(jsonp response).
how can i get the list of drivers in that response?,
like: collectionVar = response.getDrivers();.
any link or same problem links would help thanks!
Do something like this. This should work . You are getting a promise . Promises are handled like below. Learn more about promise
app.controller("testController", function($scope,testService){
testService.getDrivers ()
.then(function (response) {
$scope.standingTable = response.data.MRData.StandingsTable.StandingsLists[0].DriverStandings;
// handle valid reponse
},
function(error) {
//handel error
});
}
Big thanks for Noman! i didnt know that i was getting a angular promise response at first. though i want to get the driver standing list. so i use this code.
$scope.driversList = response.data.MRData.StandingsTable.StandingsLists[0].DriverStandings;

Angular Asynchronous Data to scope and use it in view file

I am new to angularjs. I am using Angular 1.5
I want to load data from server and store it to scope and use it in view file.
My data is stored in the scope after load the view file. How can I store data to scope first and than load the view file so that I can use scope data in view file.
Here is my code
$scope.getProfile = function() {
Account.getProfile()
.then(function(response) {
$scope.user = response.data;
console.log($scope.user); //here data printed in console
})
.catch(function(response) {
console.log(response.data.message, response.status);
});
};
if($auth.isAuthenticated()){
$scope.getProfile();
console.log($scope.user)//here data not print in console.
}
Code in .then blocks execute asynchronously after the function returns.
Have the function return a promise for the value and extract that value in a .then block:
$scope.getProfile = function() {
return Account.getProfile()
.then(function(response) {
$scope.user = response.data;
console.log($scope.user); //here data printed in console
return $scope.user;
})
.catch(function(response) {
console.log(response.data.message, response.status);
throw response;
});
};
if($auth.isAuthenticated()){
var promise = $scope.getProfile();
promise.then(function(user) {
console.log(user);
});
};
By using a promise returned by the function, a .then block can be created that will execute after the data has returned from the server.
Explaination of Promise-Based Asynchronous Operations
console.log("Part1");
console.log("Part2");
var promise = $http.get(url);
promise.then(function successHandler(response){
console.log("Part3");
});
console.log("Part4");
The console log for "Part4" doesn't have to wait for the data to come back from the server. It executes immediately after the XHR starts. The console log for "Part3" is inside a success handler function that is held by the $q service and invoked after data has arrived from the server and the XHR completes.
For more information, see How to use $http promise response outside success handler.
Demo
console.log("Part 1");
console.log("Part 2");
var promise = new Promise(r=>r());
promise.then(function() {
console.log("Part 3");
});
console.log("Part *4*");
It's because of the Async behavior, you might need to use the callbacks. Give this a try
$scope.getProfile = function(callback) { //added callback function
Account.getProfile()
.then(function(response) {
$scope.user = response.data;
callback($scope.user); //callback execution
})
.catch(function(response) {
console.log(response.data.message, response.status);
});
};
And your caller should be like following:
if ($auth.isAuthenticated()) {
$scope.getProfile(function(user){
$scope.user = user;
});
}
Hope this will help
If you want to execute some code every time an angular page loads, you could make use of ‘resolve’, as long as ‘UI-Router’ setup.
If you just want to execute some code without loading data, you are better off using ‘$viewContentLoading‘ or ‘$viewContentLoaded‘. Please note the following documentation.
You can refer here for more information
change your code as shown below:
$scope.getProfile = function() {
Account.getProfile()
.then(function(response) {
$scope.user = response.data;
console.log($scope.user); //here data printed in console
if($auth.isAuthenticated()){
console.log($scope.user)//here data not print in console.
}
})
.catch(function(response) {
console.log(response.data.message, response.status);
});
};
$scope.getProfile();
Hope this helps. :-)

manage factory JSON $http data with 2 controllers

I'm trying to get a factory JSON response, save it in a variable, in order to be ready to be called from 2 different controllers.
Here bellow I paste the code I'm using:
storyFactory.js
var story = angular.module('story.services', []);
story.factory('storyAudio', [ '$http', function ($http) {
var json = {};
function getJSON(story_id, callback) {
$http({
url: 'https://api.domain.co/get/' + story_id,
method: "GET"
}).success(function (data) {
json = data;
callback(data);
});
};
return {
getSubaudios: function(story_id, callback) {
getJSON(story_id, function(result) {
callback(result);
});
},
getTopbar: function(callback) {
callback(json);
}
};
}]);
StoryCtrl.js
var storyCtrl = angular.module('story', ['story.services']);
storyCtrl.controller('storyCtrl', [ 'CONFIG', '$stateParams', 'storyAudio', function(CONFIG, $stateParams, storyAudio) {
var data = this;
data.story = {};
storyAudio.getSubvideos($stateParams.story_id, function(response) {
data.story = response;
});
}]);
TopbarCtrl.js
var topbarCtrl = angular.module('topbar', ['story.services']);
topbarCtrl.controller('topbarCtrl', [ 'CONFIG', '$stateParams', 'storyAudio', function(CONFIG, $stateParams, storyAudio) {
var data2 = this;
data2.story = {};
storyAudio.getTopbar(function(response) {
data2.story = response;
});
}]);
The problem is in my TopbarCtrl response I'm receiving an empty data2.story when I call it in the HTML.
The reason is because it doesn't have a callback of the $http response, so it prints the var json with the actual status, that is an empty object.
How could I load the second controller when the variable has content?
Thanks in advice.
I think the best you can do in this case is load the data via getSubaudios and provide a reference to the data for other controllers to use. Something like this...
story.factory('storyAudio', function($http) {
var factory = {
story: {}
};
factory.getSubaudios = function(story_id) {
return $http.get('https://api.domain.co/get/' + story_id).then(function(response) {
return angular.extend(factory.story, response.data);
});
};
return factory;
})
Using angular.extend() instead of directly assigning a value to the factory's story property maintains any references that may be established before the data is loaded.
Then you can load the data via
storyCtrl.controller('storyCtrl', function(storyAudio) {
var data = this;
storyAudio.getSubaudios($stateParams.story_id).then(function(story) {
data.story = story;
});
})
and directly reference the story data by reference in your controller
topbarCtrl.controller('topbarCtrl', function(storyAudio) {
this.story = storyAudio.story;
})
I think I'm understanding correctly, but let me know if not.
There are two issues I'm seeing. The first is that there is a typo in your StoryCtrl.js file. You are calling "storyAudio.getSubvideos" but the function is called "getSubaudios" in your factory.
Even with that typo fixed, the issue could still technically happen. It all really depends on how quickly the promise returns from the first call. Unfortunately, promises are asynchronous, so there is no guarantee that the "json" variable will get set before the second controller tries to get it.
In order to resolve this, you need to ensure that the first call is finished before trying to access the "json" variable you have on the service. There are probably a few different ways to do this, but one that comes to mind is to actually return and store the promise in the service like so...
var dataPromise;
function getSubaudios(story_id){
if(!dataPromise){
dataPromise = $http({
url: 'https://api.domain.co/get/' + story_id,
method: "GET"
});
}
return dataPromise;
}
return {
getSubaudios: getSubAudios
};
Then in your controllers, you can just call the service and use .then to get the data out of the promise when it returns...
storyAudio.getSubaudios($stateParams.story_id).then(function(response){
data.story = response; //or data2.story = response;
});
Here is a plunkr example. I've used the $q library to simulate a promise being returned from an $http request, but it should illustrate the idea.
Similar to Phil's answer. (Angular extend, or angular copy keeps the references the same in both controllers. If you don't want to put watchers in both controllers to keep track if the value changes.) Several methods here:
Share data between AngularJS controllers.
You could also bind the object you are returning directly to the update-function. That way the references stay intact.
storyServices.factory('storyAudio', ['$http', function($http) {
return {
data: { json: '' },
getSubaudios: function(story_id) {
$http.get('http://jsonplaceholder.typicode.com/posts/' + story_id)
.then(function(response) {
this.data.json = response.data.body;
}.bind(this));
}
};
}]);
var storyCtrl = angular.module('story').controller('storyCtrl', ['$scope', 'storyAudio', function($scope, storyAudio) {
$scope.data = storyAudio.data;
storyAudio.getSubaudios(2);
}]);
var topbarCtrl = angular.module('story').controller('topbarCtrl', ['$scope', 'storyAudio', function($scope, storyAudio) {
$scope.data2 = storyAudio.data;
}]);
Plunk here: http://plnkr.co/edit/auTd6bmPBRCVwI3IwKQJ?p=preview
I added some scopes to show what happens.
Sidenote:
I think it's straight out dishonest to name your non-controller "storyCtrl" and then assign it a controller of its own:
var storyCtrl = angular.module(...); // Nooo, this is not a controller.
storyCtrl.controller(...); // This is a controller! Aaaah!
Another sidenote:
.success() is the old way of doing things. Change to .then(successCallback) today! I dare to say it's the standard convention for promises.
https://docs.angularjs.org/api/ng/service/$http#deprecation-notice

Manipulate data from promise result

var prom = $http.get('url');
prom.success(function(data){
//here calling some service and updating the data
});
$scope.abc = function(){
//doing some calculation with updated data
}
Once i get data from http request, i am calling some service which adds some info to received data. i.e data+service()=updatedData.
Now,on this updated data I am applying some calculation, and displaying it in view.
But this thing is not working. I tried to add this calculation to prom.success itself, but still I am not getting updated data. I tried setInterval() to $scope.abc but some time it display sometime won't.
Please help me to solve this problem.
Thank you
Write a method in a service that will resolve the data. In the method first call $http to get the data. After it has got the data, call the 2nd service which will add extra info. Once that is done (i.e. the promise for the 2nd service has been resolved), resolve the update data. From the controller call this method in the service, and wait for it to be resoved. When it's resoved; 'then' call your method on scope that will display the data. I will post a working fiddle for you.
You can check the fiddle here.
Service
myApp.factory('service', function($http, $q) {
var addInfoToData = function(data) {
var deferred = $q.defer();
data.updatedInfo = "Some dummy info";
deferred.resolve(data);
return deferred.promise;
};
//Dummy Method for $http call
var callApi = function() {
var deferred = $q.defer();
var dummyData = {
Id: 1,
Name: "Fake Info",
Value: 15
};
deferred.resolve(dummyData);
return deferred.promise;
}
var getData = function() {
var deferred = $q.defer();
//Replace with $http
callApi().then(function(data) {
addInfoToData(data).then(function(updatedData) {
deferred.resolve(data);
})
})
return deferred.promise;
}
return {
getData: getData
}
})
Note: callApi method is a dummy method for $http call. Replace it with your actual API call.
Controller
function MyCtrl($scope, service) {
$scope.name = 'Superhero';
$scope.abc = function(data) {
data.Value = data.Value / 100;
$scope.displayData = data;
}
var getData = function() {
service.getData().then(function(data) {
$scope.abc(data);
})
}
getData();
}

Angular Promise not working

I try to get some important things like: companyid,employeeid etc. with every request that a user makes. So this has to be received before everything else is done.
After that the user receives information based on his companyid that he sets with every request (get/company/{companyid}).
The problem that I have is that the response for receiving the companyid takes to long and angular already tries to make a request to (get/company/{companyid}) obviously there is no companyid yet.
I've tried to fix this whit promise but it's not working.
Here I try to receive some important information about the user(that I do with every request) :
Service
(function () {
angular.module('employeeApp')
.service('authenticationservice', authenticationservice);
function authenticationservice($http,$location,authenticationFactory,$q,GLOBALS,$cookies) {
this.validateUser = function () {
var vm = this;
vm.deferred = $q.defer();
data = {"api_token": api_token};
return $http.post(GLOBALS.url+'show/employee/' + $cookies.get('employeeid'),data)
.success(function(response)
{
vm.deferred.resolve(response);
})
.error(function(err,response)
{
vm.deferred.reject(err);
});
return vm.deferred.promise;
}
}
})();
Routes file
(In my routes file I use the authenticationservice to set all important users variables.)
employeeAppModule.run([
'authenticationservice',
'constants',
function(authenticationservice,constants) {
authenticationservice.validateUser()
.then(function(response)
{
constants.companyid = response.result.Employee;
constants.role = response.result.Role;
constants.name = response.result.FirstName;
console.log('test');
},
function(response){
console.log('error');
});
}
]);
So the problem is that the user information is set to late and angular already goes to my homeController where he uses the companyId that is not being set yet.
Thankyou
The problem in your current code is return $http.post are having two return statement in your validateUser method. Which is returning $http.get before returning return vm.deferred.promise; & that why customly created promise doesn't get returned from your method. Though by removing first return from $http.get will fix your problem, I'd not suggest to go for such fix, because it is considered as bad pattern to implement.
Rather I'd say, you should utilize promise return by $http method, & use .then to return data to chain promise mechanism.
Code
function authenticationservice($http, $location, authenticationFactory, $q, GLOBALS, $cookies) {
this.validateUser = function() {
var vm = this;
data = {
"api_token": api_token
};
return $http.post(GLOBALS.url + 'show/employee/' + $cookies.get('employeeid'), data)
.then(function(response) {
var data = response.data;
retrun data;
}, function(err) {
return $q.reject(err);
});
}
}
To make sure that $ http return a $ promise object you need to check that the action in the controller returns a value and it is not a void action.

Categories

Resources