I got problem to inject a service to another one, however when I tested separately it seems work fine then.
My project structure is like this, app.html includes app.js, service1.js, service2.js, and they are placed in order.
Below is my code:
app.js
var aoApp = angular.module('aoApp', []);
aoApp.run(function (permissionService, userService) {
userService.setPermissions("['admin']");
permissionService.print();
});
service1.js
var app = angular.module('aoApp');
app.service('userService', function(){
var user = {
permissions: []
};
this.setPermissions = function(permissions){
user.permissions = permissions;
};
this.getPermissions = function(){
return user.permissions;
};
return this;
});
service2.js
var app = angular.module('aoApp');
app.service('permissionService', function(userService){
var userGrantedPermissions = userService.getPermissions();
//Here always print '[]' rather '['admin']'
console.log(userGrantedPermissions);
this.print = function(){
console.log(userGrantedPermissions);
};
return this;
});
Problem is in service2.js (permissionService), parameter userGrantedPermissions is expected to be ['admin'], however its value keeps the default value '[]', I don't know if do something wrong here, but I tried to tested here, it works! so what's wrong with my code now? why doesn't it work here?
The problem is due to the execution of your code.
var app = angular.module('apps', []);
app.service('s1', function(){
console.log('in s1 ctor');
return this;
});
app.service('s2', function(s1){
console.log('in s2 ctor');
return this;
});
app.run(function(s1, s2){
console.log('executing run');
});
This will print:
in s1 ctor
in s2 ctor
executing run
Since the ctors run before the run method.
Your Fiddle example doesn't run the code the same way you do in your original example.
The original example does this in the ctor:
var userGrantedPermissions = userService.getPermissions();
Which is executed before the run method and therefore returns the init value [].
Your fiddle executes a method and doesn't run anything in the ctor.
Check out this JSFIDDLE.
Related
I have the following service:
myApp.service('myService', function(){
this.functionOne = function(){
return true;
};
this.functionTwo = function(){
// Call functionOne
};
});
I would like to call functionOne from functionTwo without having to rewrite the way the service is written (in this case, returning an object with functions).
Is there a way to do this using the this format of providing functions?
There are multiple ways to do this, but the safest is to just define a _this variable.
myApp.service('myService', function(){
var _this = this;
this.functionOne = function(){
return true;
};
this.functionTwo = function(){
var x = _this.functionOne();
};
});
In this case the variable _this references the myService object that is created by AngularJS.
The problem here is that this is a JavaScript special variable that can be assigned values. It doesn't work like it does in other languages. So unless you know what the this variable will be at the time of the closure functions execution you should just use a variable you know is safe.
app.factory('myService', function() {
var firstFn = function() {
secondFn();
//some code
}
var secondFn = function() {
//additional code
}
return {
firstFn: firstFn;
}
})
This code exposes the firstFn to wherever this service gets called. When you call firstFn, it will also run secondFn. You can access firstFn using myService.firstFn() whenever you inject this service. Hope that helps.
Note: I've used a factory instead of a service. There's a subtle yet significant difference between the two. Long story short, a factory is a bit more flexible than a service with respect to what you can do with it.
New to AngularJS and I guess I don't understand how to call one Promise method from another with the same factory. Every time my code gets to the $http.get within processPerson, I get a Function Expected error in IE, or an Object is not a Function error in Chrome. I've tried reorganizing code many times, multiple factories, etc, and generally get the same error. The only time I can get this to work is if I combine the functions where the processPerson function is embedded within the success of the getPersonnel.
Code:
(function(){
var app = angular.module('hrSite', ['personnel']);
app.controller('PersonnelController', function($scope, personnelFactory){
var personnelPromise = personnelFactory.getPersonnel();
personnelPromise.then(function(personnel){
var perDefs = new Array();
$.each(personnel.data.value, function( i, person ){
var perDef = personnelFactory.processPerson(person);
perDefs.push(perDef);
});
$q.all(perDefs).then(function(){
$scope.personnel = personnel.data.value;
});
});
});
})();
(function(){
var personnelModule = angular.module('personnel', []);
personnelModule.factory('personnelFactory', function($http, $q) {
var getPersonnel = function(){
return $http.get("/sites/Development/_api/web/lists/getbytitle('Personnel')/items");
};
var processPerson = function(person){
var deferred = $q.defer();
$http.get("/sites/Development/_api/web/lists/getbytitle('Personnel Skills')/items?$select=*,Skill/Id,Skill/Title&$filter=PersonId eq '"+person.Id+"'&$expand=Skill").then(function(skills){
person.Skills = skills.data.value;
person.SkillsId = [];
$.each(skills.data.value, function( j, skill ){
person.SkillsId.push(skill.Id);
});
deferred.resolve();
});
return deferred.promise();
};
return {getPersonnel: getPersonnel,
processPerson: processPerson}
});
})();
Nevermind - I figured it out. I was migrating code from a jQuery project and in jQuery, you return a promise like this:
return deferred.promise();
Since Angular has its own deferred feature, $q, I began using that, without realizing that the notation to return a promise was slightly different:
return deferred.promise;
No () in that, which was really screwing things up. Now everything seems to be working fine.
Folks I have my application setup as below:
var myApp = angular.module('app', []);
myApp.factory('MotorList', ['$resource', function($resource) {
return $resource(baseURL + 'MotorList.json', {}, {} );
}]);
myApp.factory('MotorDataManager', function(MotorList) {
var List;
MotorList.query().$then(function(value){
List = value.data;
})
return {
getFullList: function() {
return List;
}
anotherFunction: function { ... }
}
});
myApp.controller('MainCtrl', function($scope,MotorDataManager){
$scope.tableData = MotorDataManager.getFullList();
})
IN my front-end I have a ng-repeat that loops through $scope.tableData.
However the issue I am facing is that $scope.tableData never gets rendered. The resource is working fine. It does return data, however I feel this is a timing issue but I am not sure how to resolve it.
Certainly, this is a timing issue. When you call MotorDataManager.getFullList(), you are getting undefined because the callback which sets it never gets set. So, $scope.tableData is undefined.
You need $scope.tableData to have a reference to something that changes. Here is one way to do it:
myApp.factory('MotorDataManager', function(MotorList) {
var list = [];
MotorList.query().$then(function(value){
angular.forEach(value, function(item) {
list.push(item);
});
});
return {
getFullList: function() {
return list;
}
}
});
myApp.controller('MainCtrl', function($scope,MotorDataManager){
$scope.tableData = MotorDataManager.getFullList();
});
In this example, you are now returning an array, so to start with, $scope.tableData will be an empty array. But that will be OK, because you now have a reference to something. When the $resource returns, it will populate the array (which is the same reference) so your controller will now have a populated array. Angular's data binding and digestion logic should take care of the rest.
Plunkr
I have this service I inject in my controllers. It is simply a service to share some properties.
angular.module('app', []).
service('sharedProperties', function () {
var list_name = '';
return {
getListName: function() {
return list_name;
},
setListName: function(name) {
list_name = name;
}
};
});
I have two controllers. In the first one, I set the value of list_name. In my second, I want to retried this information.
Here is how are defined my controllers :
function ListCtrl($scope, $http, sharedProperties) {
...
$scope.changeListName = function(list_name) {
sharedProperties.setListName(list_name);
console.log(list_name, sharedProperties.getListName()); # shows ( 'metro', 'metro') == metro being a dummy list_name
...
};
function ItemCtrl($scope, $http, sharedProperties) {
...
$scope.showOnlyList = sharedProperties.getListName();
console.log(this.sharedProperties.getListName()); # empty string
...
};
I logged the variable and checked them in the browser console and noticed that ListCtrl sets the shared Property properly. The issue comes from the ItemCtrl controller. It seems that when I try to access the list_name with sharedProperties.getListName();, the property is empty, or the function returns an empty string.
UPDATE
I thought the problem came from the service. So I decided to use Lungojs' data library.
I got the following code :
In ListCtrl :
$scope.changeListName = function(list_name) {
Lungo.Data.Cache.set("ListName", list_name);
console.log('LIST', Lungo.Data.Cache.get("ListName"));
};
In ItemCtrl :
$scope.showOnlyList = Lungo.Data.Cache.get("ListName");
console.log('ITEM', Lungo.Data.Cache.get("ListName"));
The log in ListCtrl shows that the cache is set to the correct list_name. However, the console for ItemCtrl shows that Lungo.Data.Cache.get("ListName") is undefined even if it was correct on the ListCtrl!
I also tried replacing the cache by HTML5 local storage without success...
Well, I think its because you instantly log your sharedListPropery to the console, right after instantiating your ItemCtrl.
When it is instantiated, sharedPropertyList has no value yet.
EDIT:
Sry, JSFiddle is currently not working, so I have to put this untested code here.
But it should give you an idea
angular.module('app', []).
service('sharedProperties', function () {
var list_name = '';
return {
getListName: function() {
return list_name;
},
setListName: function(name) {
list_name = name;
}
};
}).
controller('ListCtrl',['$scope','sharedProperties',function(scope,shared){
console.log(shared.getListName()); //empty, because nothing set yet.
scope.listname = shared.getListName();
//watching the change and updating the shared
scope.$watch('listname',function(value){
console.log('listname is now '+value);
shared.setListName(value);
})
//watching the shared directly
scope.shared=shared;
scope.$watch('shared.getListName()',function(value){
console.log("sharedProperty has changed to"+value);
})
}]);
I decided to start learning AngularJS by making a simple app.
The server-side application is built with ExpressJs, but the resource used below (/movie/:id) are not implemented yet, so pointing to this URL will result in a 404 (Not Found) error. So only getting '/' works.
I wanted to see how a $resource behaved so I made this simple test :
var app = angular.module("app", ["ngResource"]);
app.factory("Movie", function ($resource) {
return $resource("/movie/:id");
})
app.controller("MovieCtrl", function($scope, Movie) {
$scope.test = function () {
Movie.query();
return 42;
}
});
And my template file :
<div ng-app="app">
<div ng-controller="MovieCtrl">
{{ test() }}
</div>
</div>
As expected the template is rendered and '42' is properly displayed, but if I watch the console in the Chrome developer tools I keep seeing the following error (also as expected):
GET http://localhost/movie 404 (Not Found)
But this message is printed indefinitely and never stops, as if my Movie resource keeps trying to reach /movie even though after a hundred tries it still keeps failing.
Thank you in advance.
This is because Movie.query() calls $scope.$apply() after it gets response from the server.
Everytime $scope.$apply() is called, angular does dirty checking (which again invokes test and therefore calls Movie.query() again) to find out if anything has changed. This causes an infinite loop.
move Movie.query() out from the test(), and this should work.
Let me make myself clear - take look at this pseudo code:
var watches = ['$scope.test()'];
var previous = {};
var values = {};
$rootScope.$apply = function(){
previous = values;
values = {};
var dirty = false;
for (var i =0;i<watches.length;i++){
var expression = watches[i];
values[expression] = value = eval(expression);
if(value!=previous)dirty=true;
}
if(dirty)$rootScope.$apply();
}
Movie.query = function(){
setTimeout(function(){
$rootScope.$apply();
},300);
}
$scope.test = function(){
Movie.query();
return 42;
}
so the flow is following:
$scope.apply();
$scope.test();
Movie.query(); -> setTimeout($scope.apply,100) (back to beginning );
and so on..