Use same controller method to fill different list in scope - angularjs

I am trying to use one controller method to fill different lists in my view.
var loadPlayers = function (division) {
var year = new Date().getFullYear() - parseInt(division);
console.log(year);
return PlayersService.getPlayersByDate(year).then(function(response){
return response;
});
};
$scope.playersU20 = loadPlayers(20);
$scope.playersU18 = loadPlayers(18);
PlayersService
this.getPlayersByDate = function (year) {
var promise = $http.get('/playerByYear/' + year).then(function(response) {
return response.data;
});
return promise;
};
But this is not working. It just works when I remove the return statements and just do $scope.playersU20 = response;. But this does not allow me to re-use the function. I hope I made myself clear.
Thank you

The then function returns a promise, so you'll need to update the scope in the success function invoked on promise fulfilment:
loadPlayers(20).then(function(players) { $scope.playersU20 = players; });
loadPlayers(18).then(function(players) { $scope.playersU18 = players; });
I would refactor to remove loadPlayers - it seems redundant when you can just use your players service directly in the controller if you used years rather than years ago. If you also need years ago, then add it as an additional function on your players service. You'll also want to add error handling.

Change the loadPlayers() function as following. The one you did on the question is not a re-usable function in javascript. I provide you a link to learn know about how to properly declare function in JavaScript. It will give you a better understanding not only just know how to make functions in Javascript, and also talk about the scope of functions. JavaScript Function Tutorial
function loadPlayers (division) {
var year = new Date().getFullYear() - parseInt(division);
console.log(year);
return PlayersService.getPlayersByDate(year).then(function(response){
return response;
});
};
$scope.playersU20 = loadPlayers(20);
$scope.playersU18 = loadPlayers(18);

Related

Find and return item in Angular deferred promise

So i have a bit of a confusion with angular promises.
I have a service, storing a list of users
.service('user', ['$q','$http', function ($q, $http) {
var services = {};
var _def_userLsit = $q.defer();
$http.get('/api/acc/getlist').then(function (data) {
_def_userLsit.resolve(data);
})
services.getUserListQ = function () {
return _def_userLsit.promise;
}
return services;
}])
after injecting it, i can load my list like this in a controller:
user.getUserListQ().then(function (promise) {
$scope.userHelper.userList = promise.data;
});
no problem here, got the json in the $scope, then the watchers do their jobs just fine.
Here is the Json format simplified for the question:
obj 1 { id=4, userName="foohuman", $$hashKey="object:14"}
obj 2 { id=444, userName="barhuman", $$hashKey="object:22"}
But i also want a user's name by id, and i need to run that several times ( depend on the post count ).
So my question here is, how can i return a user's name like a function call, from that promised list.
like a normal function would do, like this:
$scope.getUserById = function( id ){
return "foo";
//some magic needed here
}
If i just iterate trough the userHelper.userList, it could be empty if it runs too early, so i need to load that trough a promise, but loading it, iterating trough, then adding a string to the $scope is not the best options, since it can run multiple times, so it can overwrite each other, pretty unpredictably if i store it in a single variable.
So any idea how can i return a nice simple string by the id, and not a promise?
EDIT: Ok, so i can't really return a nice string, because it have to be some kind of callback, but i can process the data from the promise, so i ended up loading user data into a array like this:
user.getUserListQ().then(function (promise) {
var uArr = [];
angular.forEach(promise.data, function ( value, key ) {
uArr[value.id] = value.userName;
})
$scope.userHelper.uArr = uArr;
});
and in the html I can boldly write {{userHelper.uArr[taskData.tOwner]}}.
First of all, you're making promises harder than they should be by using the explicit construction antipattern. Your first code snippet can be replaced with this:
.service('user', ['$q','$http', function ($q, $http) {
var services = {};
var pUserList = $http.get('/api/acc/getlist');
services.getUserListQ = function () {
return pUserList;
};
return services;
}]);
Regarding your question:
So any idea how can i return a nice simple string by the id, and not a promise?
This is the wrong mindset to have. For getting a user by their ID, you need to think in terms of promises. You don't know exactly when the data is going to be ready, so this means that your getUserId method should return a promise. You can write it like this:
services.getUserById = function (id) {
return pUserList.then(function (users) {
return users.filter(function (user) { return user.id === id; })[0];
});
};
in your controller, you can use it like this:
myService.getUserById(4).then(function (user) {
$scope.myUser = user;
});

Angular - Moving function into a service

I have a function that I'm now needing to use in multiple page so decided to move into a service - however its not going as I'm expecting.
So in my HTML i have:
<li ng-init="bg = underQBar(work.options)">
Then in the controller (before I moved the common function) it looked like:
$scope.underQBar = function(toWorkArray) {
//some implementation, with a return at the end
}
Now I've made my service:
function barService($window){
var self = this;
self.getBarColours = function(toWorkArray) {
//copied the implementation with the return here
}
}
And therefore trying this in my controller:
$scope.underQBar = barService.getBarColours(toWorkArray);
However this doesnt work, its not getting the parameter I'm sending from the HTML - is this a trivial fix or something wrong with the implementation?
This is the problem:
$scope.underQBar = barService.getBarColours(toWorkArray);
Here, you're assigning the result of the service function call to $scope.underQBar, when you meant to assign it the function itself.
This should work:
$scope.underQBar = barService.getBarColours;
If you want to make it more clear to the reader that it's a function, just do:
$scope.underQBar = function (toWorkArray) {
return barService.getBarColours(toWorkArray);
}
Here is a correct definition for your service :
angular.module("myModule").factory("BarService", ["$window", function($window){
var service = {};
service.getBarColours = function(toWorkArray){
//copied the implementation with the return here
};
return service;
}]);
And here is a correct way to inject the service in your controller :
angular.module("myModule").controller("controllerName", ["BarService", function(BarService){
var self = this;
self.getBarColours = BarService.getBarColours;
}]);
and here is the way to use it:
<li ng-init="bg = controllerName.underQBar(work.options)">
Explanation :
A service or a factory in angular cannot be accessed by your view. Your view can only make a call to your controllers.
If your function should have been called by many controllers, you can put this function in a global controller that will be responsible for controlling your whole view.

angularJS: Function in function

Hello I'm new in angularJS. Suitable or not to implement function inside function?
For example like this:-
$scope.loadDistrict = function(id) {
// statement
$scope.loadBasedOnYear = function(y_id) {
console.log(y_id);
// statement
};
};
If you bind method on scope, it's available from view.
From your code
$scope.loadDistrict = function(id) {
// statement
$scope.loadBasedOnYear = function(y_id) {
console.log(y_id);
// statement
};
};
loadBasedOnYear won't available until loadDistrict is called.
It's very bad pattern to follow.
It is possible but without context I don't really know why you would do this, calling $scope.loadBasedOnYear before calling $scope.loadDistrict will result in an error so be careful with such a design pattern.
Yes this is fine.
You should watch out for when the function will be executed outside of angular's cycle. E.g. if you do:
setTimeout(function() { $scope.test = 5; }, 1000);
If you need to do this then you need to wrap the function in $scope.$apply(), or use $timeout.

How to return a new key onchange location in angularjs

The idea is to always have a new key as soon as you change the page, this is my code but I think I have problem
$scope.newKey =function (){
var key =0;
$rootScope.$on('$locationChangeSuccess', function () {
key++ ;
});
return key;
};
If one of you has already tried $locationChangeSuccess it can help me thank you
Why don't you try using angular's service or factory, so that it includes the Scope variable key which is actually globally available to the entire app/module? i mean this is just my view though
I'm not pretty sure - how exactly you want to use your "newKey", but if you need it on your html, then the valverde93's answer is correct:
$scope.newKey = 0; $rootScope.$on('$locationChangeSuccess', function () { $scope.newKey++; });
And on your html:
{{newKey}}
But if you want to use it on your backend (the js files like a function) - then you get always $scope.newKey = 0, just because you're put your console.log after the incrementation function, and you see only the $scope.newKey = 0;
So if you put your console.log in the function - something like:
$rootScope.$on('$locationChangeSuccess', function () { $scope.newKey++; console.log($scope.newKey);});
then you'll see your proper key.
Or you may to use $watch, to check when the scope is changed and to do somthing:
$scope.$watch('newKey', function(newValue ) {
console.log( newValue );
}
);
Good luck.

Can I use a factory within another factory to join two REST requests together?

I have two factories as follows:
angular.module('categoryResource', ['ngResource', 'userResource'])
.factory('categories', function ($http, users){
var factory = {};
factory.getCategories = function () {
return $http.get('/api/userCategories');
};
factory.getCategoriesUsers = function () {
//call factory.getCategories(), parse the request to make it nice and tidy
//then call users.getUsers(), tidy them up in the same way as categories, join them together and return them all in a nice package.
};
var handleCategoriesUsers = function (data, status) {
}
return factory;
});
angular.module('userResource', ['ngResource'])
.factory('users', function ($http) {
var factory = {};
factory.getUsers = function () {
return $http.get('/api/users');
};
return factory;
});
I've already made a nice treeView with the Categories but I want to also add Users to those categories; so to this end I thought I'd just format the users into something my treeView algorithm can already work with.
My question is, Can I somehow do It within the categories factory (or even a different module/factory altogether) and just return the joined results at the same time? If yes, how? Do I need to define a handler for $http.get like I usual? then in that handler, call the other get then define a handler for that and then return the result?
I'm not 100% sure I understand the question, but have you looked at $q.all? It seems like you want to compose/combine multiple promises into a single, easy to handle package. I'd give you a description and some code samples, but egghead did it better: https://egghead.io/lessons/angularjs-q-all
Is this what you're looking for?
EDIT: In case just dumping a link is frowned upon:
var all = $q.all([one.promise, two.promise, three.promise]);
all.then(success)
function success(data) {
console.log(data);
}

Resources