I'm trying to get some data from a Service into a Controller and I keep get an undefined variable.
angular
.module("classes")
.service("MyService", function ($http) {
this.foo;
$http.get("/classes/all").then(function (response) {
this.fighters = response.data;
this.foo = this.fighters;
console.log(this.foo);
});
console.log(this.foo);
})
When I run this I get on the console, by this order, line 11 is undefined and then line 9 returns me the array.
And when in the controller I try to get the variable foo, it also says undefined.
$scope.fooFighters = MyService.foo;
The reason is because of asynchronous execution of your API call. I would suggest you to rewrite the code to use a factory that will return a promise object. No need to bring unnecessary variables.
angular.module("classes").factory("MyService", function($http) {
return {
fighters: function() {
return $http.get("/classes/all").then(function(response) {
return response.data;
});
}
}
})
And in your controller, you can get the value by injecting the service in the controller and then by referencing it like
MyService.fighters().then(function(data){
$scope.fooFighters = data;
});
because it will take some time to load the ajax/http request data after that line 9 will work. So if you want to work with ajax/http data then you should write code/function inside
$http.get("/classes/all").then(function (response) {
// do something
});
Related
I'm trying to use a 1.5 component with AngularJS. I have a service that gets my JSON file using $HTTP and returns the promise. I then resolve the promise in my components controller and assign it to a value on the controller using this.work. Although this doesn't show in my HTML page. I have included comments in the code to explain a little better if this is confusing.
It's my understanding that the resolving of the promise (in my controller) is happening asynchronously but once it's resolved why am I not shown the updated changed to the variable $ctrl.work in the view. Instead I never get a value from the variable.
// Component
(function () {
angular.module('development')
.component('pgDev', {
templateUrl: 'app/development/development.template.html',
controller: ['workList', function (workList) {
//this.work = 'HELLO WORLD'; // <- this shows up in the html if uncommented
workList.getWorkItems().then(function (d) {
console.log(d.test); // outputs: myjsonfile
this.work = d.test; // <- this doesnt show in the html
});
}]
})
}());
// HTTP Get Service
(function () {
angular.module("development").factory("workList", ["$http",
function ($http) {
return {
getWorkItems: function () {
return $http.get("data/worklist/worklist.json").then(function (d) {
return d.data;
});
}
}
}])
})();
// html
workitems: {{$ctrl.work}}
You are loosing context of execution which means that this inside your callback function if not and instance of component controller. A simple (and modern) solution is to use arrow function instead of normal anonymous:
workList.getWorkItems().then(d => {
this.work = d.test;
});
I'm trying to get a list of all the 'cashflow' objects in my django application by calling a AngularJS get function every 5 seconds. I run the function with $interval(getCashflows, 5000); in my js file and try to display it in my html as [[getCashflows]] (see interpolateprovider)
Now the only thing I get is "[[getCashflows]]" in my html.. does interpolateProvider not work or do I need to call it differently?
app = angular.module("coco",[]);
app.config(function($interpolateProvider) {
$interpolateProvider.startSymbol('[[');
$interpolateProvider.endSymbol(']]');
});
app.controller('cocoCtrl',['$scope','$http', function($scope) {
$scope.save = function (cashflow) {
var dataObj = {
value : cashflow.value,
date : cashflow.date,
};
$.ajax({
url : "/create_cashflow/", // view functie
type : "POST",
data : dataObj,
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
},
success : function(json) {
$(".data").prepend("<li><strong>"+json.value+"</strong> - <em> "+json.date+"</em></li>");
}
});
}
}]);
app.controller('cocogetCtrl',['$scope','$http', function($scope,$http, $interval) {
$scope.cashflows = "";
$interval($scope.getCashflows = function() {
return $http.get("/get_cashflows/", {data:data}).then(function(response) {
$scope.cashflows = "test";
alert(response.toString());
$(".flows").prepend("<li><strong>"+json.value+"</strong> - <em> "+json.date+"</em></li>");
return response.toString();
});
}, 5000);
}]);
Your problem is almost certainly that you are attempting to update an angular scope variable from a jQuery callback. Angular only checks for changes to the scope inside its own digest loops and the callback will happen outside that context so angular doesn't see the change.
The simple fix is to stop using $.ajax() calls and start using the $http service that you have already included in your controller.
However it isn't at all clear what you expect to see in your html. The function getCashflows isn't returning a value, either as written or indeed if you rewrite it to use $http. The value is retrieved from the server asynchronously. You should change it so that the scope value is a promise which resolves to the expected value. As $http already returns a promise it should be sufficient to do something like:
function getCashflows() {
$scope.cashFlows = $http.get("/get_cashflows/", {data:data})
.then(function(response) {
return response.data;
});
}
The change your html to interpolate the value cashFlows instead of the function.
There is probably no reason for getCashflows itself to be exposed to the scope, you could just make it an ordinary function which will have the side effect of fixing the call to $interval that will currently just cause the javascript to stop due to an unresolved name.
I'm trying to use AJAX to bring in some data and then modify it before sending the result to a controller. I had this all working in the controller but I was told that it's better to do it in a service.
app.factory('GameweekJsonFactory', ['$http',function($http){
var promise;
var service = {
async: function() {
if ( !promise ) {
promise = $http.get('jsons/gameweeks.json').then(function(response){
return response.data
});
}
return promise;
}
}
return service;
}]);
Then in another factory I wanted to change the value of a variable dependent on the response of the AJAX call. (Say for example if it's gameweek 6 going by date, I want gwk to equal 6).
app.factory('GameweekFactory',['GameweekJsonFactory',function(GameweekJsonFactory) {
var gwk;
var obj = {
foo: function(){
GameweekJsonFactory.async().then(function(d){
//Code here to find out the current gameweek.
gwk = 6;
return gwk;
});
}
};
return gwk;
}]);
controller: function(GameweekFactory){
console.log('Controller Log '+GameweekFactory)
},
How do I then modify the original gwk variable in the factory's scope? I can't work it out and I've been googling for ages!
You are not defining the factory correctly. AngularJS factories are functions that return a value, and in this case it's an object with a method named foo.
Promises are chainable. The value returned by a success callback is passed into the next success callback. So you can manipulate the value (add gwk) and return that value.
app.factory('GameweekFactory',[
'GameweekJsonFactory',
function(GameweekJsonFactory) {
return {
foo: function(){
return GameweekJsonFactory.async().then(function(d){
//Code here to find out the current gameweek.
d.gwk = 6;
return d;
});
}
};
}]);
controller: function(GameweekFactory){
GameweekFactory.foo().then(function(d){
console.log('Controller Log '+d.gwk)
});
}
I'm trying to retrieve a list of options from our database and I'm trying to use angular to do it. I've never used services before but I know that's going to be the best way to accomplish what I want if I'm going to use data from my object in other controllers on the page.
I followed a couple tutorials and put together a factory that makes an http request and returns the data. I've tried several ways of doing it, but for some reason nothing is happening. It's like it never runs the factory function and I can't figure out why.
Factory:
resortModule= angular.module('resortApp',[]);
resortModule.factory('locaService',['$http', function ($http){
var locaService= {};
locaService.locations = {};
var resorts = {};
locaService.getLocations=
function() {
$http.get('/url/url/dest/').success(function (data) {
locaService.locations = data;
});
return locaService.locations;
};
return locaService;
//This is a function I would like to run in addition to the first one so multiple variables would be stored and accessible
/*getResorts:
function(destination) {
$http.get('/url/url/dest/' + destination.id).success(function (data) {
resorts = data;
});
return resorts;
}*/
}]);
resortModule.controller('queryController',['$scope', 'locaService', function($scope, locaService) {
$scope.checkConditional= function (){
if($("#location").val() == ""){
$("#location").css('border','2px solid #EC7C22');
}
};
$scope.selectCheck= function (){
$("#location").css('border','2px solid #ffffff');
$(".conditional-check").hide();
};
$scope.resort;
$scope.locations= locaService.getLocations();
}]);
I just want the data to be returned and then assigned to the $scope.locations to be used for ng-options in the view. Then I want my other function to run on click for the next field to be populated by the variable resort. How would I do this? Any help would be great! Thanks!
$http service returns a promise, and your function should return that promise. Basically your getLocations function should be something like the following
locaService.getLocations=
function() {
return $http.get('/url/url/dest/');
};
Then in your controller you should retrieve the options using this promise:
locaService.getLocations()
.then(
function(locations) // $http returned a successful result
{$scope.locations = locations;}
,function(err){console.log(err)} // incase $http created an error, log the returned error);
Using jquery in controllers or manipulating dom elements in controllers is not a good practice, you can apply styles and css classes directly in views using ng-style or ng-class.
Here is an example how all it should look wired up:
resortModule= angular.module('resortApp',[]);
resortModule.factory('locaService',['$http', function ($http){
var locaService= {
locations: {}
};
var resorts = {};
locaService.getLocations= function() {
return $http.get('/url/url/dest/');
};
return locaService;
//This is a function I would like to run in addition to the first one so multiple variables would be stored and accessible
/*getResorts:
function(destination) {
$http.get('/url/url/dest/' + destination.id).success(function (data) {
resorts = data;
});
return resorts;
}*/
}]);
resortModule.controller('queryController',['$scope', 'locaService', function($scope, locaService) {
/* Apply these styles in html using ng-style
$scope.checkConditional= function (){
if($("#location").val() == ""){
$("#location").css('border','2px solid #EC7C22');
}
};
$scope.selectCheck= function (){
$("#location").css('border','2px solid #ffffff');
$(".conditional-check").hide();
};
*/
$scope.resort;
locaService.getLocations()
.then(
function(locations) // $http returned a successful result
{$scope.locations = locations;}
,function(err){console.log(err)} // incase $http created an error, log the returned error);
}]);
Below is the recommended way to get data into a controller from a factory using $http -- according to https://github.com/johnpapa/angularjs-styleguide
What i don't get is how the two success callbacks on $http work (i commented what i think the two callbacks are).
1) What is the point of the first callback?
2) Where does vm.avengers point to? Is it a reference to another object?
3) is 'data' in the second callback = 'response.data.results' from the first?
4) I'm counting 3 total callbacks chained, is that correct?
P.S. i already know about promises, but want to learn this pattern specifically
The factory
/* recommended */
// dataservice factory
angular
.module('app.core')
.factory('dataservice', dataservice);
dataservice.$inject = ['$http', 'logger'];
function dataservice($http, logger) {
return {
getAvengers: getAvengers
};
function getAvengers() {
return $http.get('/api/maa')
.then(getAvengersComplete)
.catch(getAvengersFailed);
//Callback One
function getAvengersComplete(response) {
return response.data.results;
}
function getAvengersFailed(error) {
logger.error('XHR Failed for getAvengers.' + error.data);
}
}
}
The Controller
function Avengers(dataservice, logger) {
var vm = this;
vm.avengers = [];
activate();
function activate() {
return getAvengers().then(function() { //Callback 3
logger.info('Activated Avengers View');
});
}
function getAvengers() {
return dataservice.getAvengers()
.then(function(data) { //Callback 2
vm.avengers = data;
return vm.avengers;
});
}}
The point of this first callback is to do any manipulation with the data prior to it entering into the app and to actually pull the useful data out of the http response object.
vm.avengers is declared at the top of your controller. It's using the "controller as" syntax and is being put on a reference to the "this" object of the controller. You're ultimately using vm.avengers to access the data in the view.
Correct.
HTTP Call -> getAvengersComplete -> getAvengers, so correct 3 callbacks.