Angularjs variable undefined outside of function - angularjs

Whenever I call the cardslength variable or just cards.length, I get undefined outside of the function. Does this mean I need to use $scope? I am using angular 1.0.5 btw because this is part of a tutorial I am following and I needed to use that version.
This is my code:
eventsApp.factory('eventData', function ($resource, $q) {
var resource = $resource('/data/event/:id', {id: '#id'});
//////////////////////This is the part that doesn't seem to be working//////////
var cardslength
var cards = resource.query(function() {
cardslength = cards.length;
});
console.log(cardslength);
console.log(cards.length);
////////////////////////////////////////////////////////////////////////////////
return {
getEvent: function () {
var deferred = $q.defer();
resource.get({id: 1},
function (event) {
deferred.resolve(event);
},
function (response) {
deferred.reject(response);
});
return deferred.promise;
},
save: function(event) {
var deferred = $q.defer();
event.id = 1234;
resource.save(event,
function(response) { deferred.resolve(response);},
function(response) { deferred.reject(response);}
);
return deferred.promise;
}
};
});

Your console.log is executed before the .query() finishes. In order to avoid this, try as follows:
var cards = resource.query(function() {
cardslength = cards.length;
}).then(function(){
console.log(cardslength);
console.log(cards.length);
});

Related

Pass parameters from $get promise response to $scope

I do a ajax (get) request and obtain a promise with json data in a angular "jobList" service.
Then I update the scope with the obtained data. But my problem is that to update a scope variable 'X' I need to create a function per variable "readX" (see bellow).
Is there a way to add parameters, like in the last function in the following code?
app.controller("JobListController", ['$scope', '$timeout', 'jobList',
function ($scope, $timeout, jobList) {
var readList = function (response) {
if (response) {
$timeout(function () {
$scope.list = response;
$scope.$apply();
});
}
};
var readFamilies = function (response) {
if (response) {
$timeout(function () {
$scope.allFamilies = response;
$scope.$apply();
});
}
};
var readRegions = function (response) {
if (response) {
$timeout(function () {
$scope.allRegions = response;
$scope.$apply();
});
}
};
// !!! ----- HERE ------------- !!!
var readSomething = function (response, something) {
if (response) {
$timeout(function () {
$scope[something] = response;
$scope.$apply();
});
}
};
jobList.get().then(readList);
jobList.getAll("allFamilies").then(readFamilies);
jobList.getAll("allRegions").then(readRegions);
}]);
For a start you could simplify those callback functions: provided the callback happens inside angular (and it you're using $http it will) you don't need the $timeout call nor the $scope.$apply() call. Also you should write your service to only succeed if it returns data, reject the promise if it fail;s and that way you don't need the if So each callback could just be the assignment.
If you are making multiple calls that return promises, can you collapse the calls together?
$q.all([jobList.get(), jobList.getAll("allFamilies"), jobList.getAll("allRegions")])
.then(([list, families, regions]) => {
$scope.list = list;
$scope.allFamilies = families;
$scope.allRegions = regions;
});
I used es6 syntax here: it's well worth setting up your build chain to use something like babeljs so you can use the shorthand notation for simple callbacks.
If you really want to make the calls separately (they still evaluate in parallel) you can write a factory to generate the callbacks:
function assignToScope(name) {
return success;
function success(data) {
$scope[name] = data;
}
}
jobList.get().then(assignToScope('list'));
jobList.getAll("allFamilies").then(assignToScope('allFamilies'));
jobList.getAll("allRegions").then(assignToScope('allRegions'));
you could save the required property in a scope variable, before getting the data.
Something like this:
$scope.property = "list";
jobList.get().then(readSomething);
and your function would now become:
var readSomething = function (response) {
if (response) {
$timeout(function () {
$scope[$scope.property] = response;
$scope.$apply();
});
}
};
P.S:
I guess you can also use closures to do something like this:
var readSomething = function (something) {
return function(response){
if (response) {
$timeout(function () {
$scope[something] = response;
$scope.$apply();
});
}
}
};
Try this:
jobList.get().then(function (response) {
readSomething(response);
});
And function readSomething can have response only as in input.

data is undefined in the controller

I'm trying to display a date that I'm getting from a server, I'm able to retreive it and display it correctly in the service but in my controller it's undefined would you help me to get this fixed.
here is my service
function footerService($http,$filter) {
var dateFormat = 'yyyy-MM-dd';
var statusDate = {};
statusDate.getStatusDate = function() {
$http.get(_contextPath + "/getDate", {}).success(
function(response) {
console.log('response', response)
statusDate.Date = $filter('date')(
new Date(response.Date), dateFormat);
console.log('Date', statusDate.Date)
return statusDate.Date;
});
};
return statusDate;
};
and in my controller
function footerController($scope,footerService) {
$scope.myDate = footerService.getStatusDate();
console.log('$scope.myDate', $scope.myDate);
};
You can use $q.defer :
function footerService($http,$filter) {
var dateFormat = 'yyyy-MM-dd';
var statusDate = {};
statusDate.getStatusDate = function() {
var deferred = $q.defer();
$http.get(_contextPath + "/getDate", {}).success(
function(response) {
statusDate.Date = $filter('date')(
new Date(response.Date), dateFormat);
deferred.resolve(statusDate.Date );
});
return deferred;
};
return statusDate;
};
And then:
footerService.getStatusDate()
.then(function(data) {
$scope.myDate = data;
});
function footerService($http, $filter) {
return {
getStatusDate = function() {
return $http.get(_contextPath + '/getDate', {});
}
};
}
function footerController($scope, footerService) {
$scope.myDate;
footerService.getStatusDate().then(function(response){
$scope.myDate = response.data.Date;
}).catch(function(response){
//error
});
}
Using $http means using async Promises.
You can define what happens when the async call is successful using then :
footerService.getStatusDate()
.then(function(receivedDate) {
$scope.myDate = receivedDate;
console.log('$scope.myDate', $scope.myDate);
});
Plus don't forget the return in getStatusDate (return $http.get...).
More info about async Promises : https://docs.angularjs.org/api/ng/service/$q
Since .success(function(){}) is the callback so you can not return any value from there. The best solution for it to pass one successCallback from controller to getStatusDate and pass the expected response from .success(function(response){}) to successCallback.
By doing this you will be able to get the service response in your controller.
Code is attached below:
function footerService($http,$filter) {
var dateFormat = 'yyyy-MM-dd';
var statusDate = {};
statusDate.getStatusDate = function(successCallback) {
$http.get(_contextPath + "/getDate", {}).success(
function(response) {
successCallback($filter('date')(new Date(response.Date), dateFormat));
});
};
return statusDate;
};
function footerController($scope, footerService) {
function successCallback(res) {
$scope.myDate = res;
console.log('$scope.myDate', $scope.myDate);
}
footerService.getStatusDate(successCallback);
};
In the service you need to return the promise from the $http request.
Try:
function footerService('$http', [$http]) {
var statusDate = {};
getStatusDate = function() {
return $http.get(_contextPath + "/getDate", {})
};
return {
getStatusDate: getStatusDate
};
};
And your controller like this:
function footerController($scope,footerService) {
footerService.getStatusDate().then(function(results) {
$scope.myDate = results.data;
});
$scope.$watch(function() {return $scope.myDate;}, function() {
console.log('$scope.myDate', $scope.myDate);
});
};
And you would apply your filter logic in the .then() method in the controller.

Validating returned value in controller instead of doing in service

I am having a method in my service as below.
module.service('Service', function($state, $rootScope) {
var getRemoteItems = function(page, displayLimit) {
var defferer = $q.defer()
var query = new Parse.Query("Item");
query.limit(displayLimit);
query.skip(page * displayLimit);
query.descending("createdAt");
var items = [];
query.find({
success: function(results) {
//process results
return results;
},
error: function(e) {
return null;
}
});
}
}
Although it's working, I am trying to make changes so that in the controller which calls this method, can use success and failure checks instead of doing it in the service method.
I am not able to understand how to use promises in this example. I am expecting somehting like below.
Service.getRemotItems(1,10).then()...error()..
Please excuse me for any syntax issues in the example as I am new to Angular.
You've already created the promise with $q.defer() you just need to resolve/reject it in the success & error callbacks
module.service('Service', function($state, $rootScope, $q) {
var getRemoteItems = function(page, displayLimit) {
var deferred = $q.defer();
var query = new Parse.Query("Item");
query.limit(displayLimit);
query.skip(page * displayLimit);
query.descending("createdAt");
var items = [];
query.find({
success: function(results) {
deferred.resolve(results);
},
error: function(e) {
deferred.reject(e);
}
});
return deferred.promise;
}
}

Angularjs : call services method inside a function

I have this simple function js getItems(), inside I call a services items.getItems(..) ,
I would like that the function return me a data. I tried to associate the var to function but the result is undefined
function getItems() {
var resolvedValue;
var deferred = $q.defer();
items.getItems(function(data) {
deferred.resolve(data);
});
deferred.promise.then(function(result) {
resolvedValue=result; // it contains my information
});
console.log('v alue%0' , resolvedValue); // it's undefined here!!!
}
items.getItems is async, so you have to use $q.promise
function getItems() {
var deferred = $q.defer();
items.getItems(function(data) {
deferred.resolve(items);
});
return deferred.promise;
}
Read more here http://docs.angularjs.org/api/ng.$q

Angular Service Definition: service or factory

I am an angular newbie, I am building an application, one thing really puzzling me is there are couple of ways of defining a service, and I read more from this link: How to define service
then it seems there is no big difference among the ways of defining a service.
but I just noticed one difference which I think is different:
see this service I get from here http://jsfiddle.net/2by3X/5/
var app = angular.module('myApp', []);
app.service('test', function($timeout, $q) {
var self = this;
this.getSomething = function() {
return self.getData().then(function(data) {
return self.compactData(data);
});
};
this.getData = function() {
var deferred = $q.defer();
$timeout(function() {
deferred.resolve("foo");
}, 2000);
return deferred.promise;
};
this.compactData = function(data) {
var deferred = $q.defer();
console.log(data);
$timeout(function() {
deferred.resolve("bar");
}, 2000);
return deferred.promise;
};
});
if I define this service using "factory" like below, one function cannot call other functions of the service.
app.factory('test', function($timeout, $q) {
return {
getSomething : function() {
return getData().then(function(data) {
return compactData(data);
});
},
getData : function() {
var deferred = $q.defer();
$timeout(function() {
deferred.resolve("foo");
}, 2000);
return deferred.promise;
},
compactData : function(data) {
var deferred = $q.defer();
console.log(data);
$timeout(function() {
deferred.resolve("bar");
}, 2000);
return deferred.promise;
},
};
});
I will get this in the browser console:
[08:41:13.701] "Error: getData is not defined
.getSomething#http://fiddle.jshell.net/_display/:47
Ctrl1#http://fiddle.jshell.net/_display/:75
invoke#http://code.angularjs.org/1.0.0/angular-1.0.0.js:2795
instantiate#http://code.angularjs.org/1.0.0/angular-1.0.0.js:2805
Can anyone explain this? thanks.
you have two big problems there:
the factory returns an object with incorrect syntax.
javascript scope of variables is functional
That is,
You should be returning an object like {key: value, key: value}
values can be functions. however, you return {key = value, key = value}
First fix:
return {
getSomething : function() {...},
getData : function...
}
Secondly, not being able to call functions is normal. See this jsfiddle. I mocked everything. You can call one of the functions returned by the service. However, when from getSomething try to call getData, you get "undefined":
app.factory('testSO', function () {
return {
getSomething: function () {
console.log('return getsomething');
getData();
},
getData: function () {
console.log('return getData');
}...
This would be the same as declaring everything in the scope of the factory function and return references see in jsfiddle:
app.factory('testSO', function () {
var getSomething = function () {
console.log('return getsomething');
};
...
return {
getSomething: getSomething,
...
}
and now you can call local functions as shown in the final version of the jsfiddle:
app.factory('testSO', function () {
var getSomething = function () {
console.log('return getsomething');
getData();
};
...
The original service has something important in it: var self = this; . Some people use var that = this. It's a workaround for an error in ECMA.
In the case of the original code, it's used to "put everything in one object". Functions (properties that happen to be functions) in self need a reference to know where the function you want to call is. Try it yourself here http://jsfiddle.net/Z2MVt/7/

Resources