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.
Related
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
});
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 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);
}]);
I've been having a problem with trying to keep my model separate from my controller because of lack of sync between model and view. I have looked around and found that most of the time an apply would solve the issue. However, apply does not work at all for me (either when called from the root scope or the relevant scope using chrome). In this link I have a demo of pretty much the problem I have on my program but instead of intervals my program has asynchronous requests or just complicated functions that seem to also be missed by angular. In the demo I have 4 variables that should be getting updated on the view. One that is being watched by the scope, another that is being updated through a callback, another that is just plain dependent on the model and one that is being updated by passing the scope itself to the service. Out of the 4 only the callback and passing the scope to the service are the ones that update the view, even when I run apply after each update (on top of the one that already runs after each execution of $interval). What I'm trying to avoid is using tons of callbacks or promises whenever my data changes due to transformations since I have many different transformations that are possible. Is there anyway to do this or are callbacks and promises the only option?
var test = angular.module("tpg",[]);
test.controller("myctrl", function($scope, $interval, service)
{
$scope.$watch(service.list.name, function()
{
$scope.name=service.list.name;
});
$scope.op=service.list.op;
$scope.call=service.list.call;
$scope.scope=service.list.test;
$scope.update=function()
{
service.getValues(function(op){$scope.op=op}, $scope);
};
}).factory("service", function($interval, $rootScope)
{
return {
list:{name:"OPA", op:"TAN", call:"1", test:"scope"},
getValues:function(callback, $scope)
{
var self=this;
var interval = $interval(function()
{
if(self.count>2)
{
$interval.cancel(interval);
self.count=0;
self.list={name:"OPA", op:"TAN", call:"1"};
}
else
{
self.list=self.values[self.count];
callback(self.list.op);
$scope.scope=self.list.test;
console.log(self.list);
self.count++;
}
$rootScope.$$phase || $rootScope.$apply();
},2000);
},
values: [{name:"guy", op:"ungly", call:"2", test:"scope1"}, {name:"TAL", op:"stink", call:"3", test:"scope2"}, {name:"tes", op:"test", call:"4", test:"scope3"}],
count:0
};
});
You need only a callback function to be returned from a service. $scope.$apply is not required when dealing with angular services as the service itself triggers the digest run. So I modified the code to remove the $apply and the promise and had a simple callback returned from the service which is then updating the view with the returned data.
Code:
$scope.update=function()
{
service.getValues(function(data){
$scope.name = data.name;
$scope.op=data.op;
$scope.call=data.call;
$scope.scope=data.test;
});
};
}).factory("service", function($interval, $rootScope)
{
return {
list:{name:"OPA", op:"TAN", call:"1", test:"scope"},
getValues:function(callback){
var self=this;
var interval = $interval(function()
{
if(self.count>2)
{
$interval.cancel(interval);
self.count=0;
self.list={name:"OPA", op:"TAN", call:"1"};
}
else
{
self.list=self.values[self.count];
console.log(self.list);
callback(self.list);
self.count++;
}
},2000);
},
values: [{name:"guy", op:"ungly", call:"2", test:"scope1"}, {name:"TAL", op:"stink", call:"3", test:"scope2"}, {name:"tes", op:"test", call:"4", test:"scope3"}],
count:0
};
});
Working plunkr
I have a simple angular $http.get, which returns a json object, but I want the id from the json to do another $http.get. I can do this by nesting another $http.get with the first one, but this seems rather stupid. What is the best way to assign the id of the response, data.id, to a variable? I'm having some issues with variable scope; trying to simply assign the value to a variable.
$http.get('/api/v1/foo/userinfo?thunk='+thunk+'&bar='+bar).success(function(data) {
$scope.id = data.id
}).then(function(data){
$scope.id = data.data.id
});
Why don't you watch your variable, in this case $scope.id like this:
$scope.$watch('id', function() {
// Http request goes here
$http.get(...)
});
When you assigned any value to $scope.id your "watch function" will be triggered.
Can use callbacks to make it cleaner. Wrap your call in a function:
function startAJAX(thunk, bar, callback) {
$http.get('/api/v1/foo/userinfo?thunk='+thunk+'&bar='+bar).success(function(data) {
callback(data.id);
});
}
Then make the call and do your next http call:
startAJAX(thunk, bar, function(id) {
$http(id).....
});
});
Using a watch() method isn't necessary. Use callbacks, or if you want to be fancy use promises to keep things organized.
var callOnePromise = $http.get('/api/foo');
var callTwoPromise;
callOnePromise.success(function(data) {
callTwoPromise = $http.get('/api/bar/' + data.id);
});
callTwoPromise.success(function() {
//Cool stuff here.
});