We have been developing a big product with AngularJS and only recently tried to use use closure compiler for syntax checking with the help of jsdoc comments.
I ran into this problem and can't find any help online, including in SO.
Consider a model class written as a service, and using the class name as a type:
ourmodule.factory('OurModel', function() {
/**
* #constructor
*/
var OurModel = function() {};
return OurModel;
});
ourmodule.controller('Controller1', ['$scope', 'OurModel', function($scope, OurModel) {
/**
* #return {OurModel}
*/
$scope.getNewModel = function () {
return new OurModel();
}
}]);
Closure compiler can't recognize 'OurModel'. What am I missing ?
Closure compiler can't guess that the OurModel that you inject to your controller is the same you declared in the factory, angularJS injection pattern make closure compiler useless in that case.
If you declare OurModel in the parent scope, no warning:
var ourmodule = {
factory: function(a, b){},
controller: function(a, b){}
};
/**
* #constructor
*/
var OurModel = function(){};
ourmodule.controller('Controller1', ['$scope', function($scope) {
/**
* #return {OurModel}
*/
$scope.getNewModel = function () {
return new OurModel();
}
}]);
Related
I have 2 js files namely collegeApp.js and branchApp.js. I have two controllers CollegeController.js which is inside collegeApp.js ng-app and BranchController.js which is inside branchApp.js ng-app.
From my html I am redirecting to another page.
Here is my html
<li data-ng-click="getBranchByBranchId(branch.branchId); setBranchId(branch.branchId)">
{{branch.branchName}}
</li>
This html page is in collegeApp.js.After clicking on branch name I am calling method And its controller looks like this.
CollegeController.js
var CollegeController = function($scope, $rootScope, $http, $location, $route,CollegeService,$routeParams) {
$rootScope.pageTitle = $route.current.title;
$scope.getBranchId = function() {
CollegeService.getBranchId().then(function(response) {
$scope.branchId = response.data;
});
}
$scope.setBranchId=function(branchId) {
CollegeService.setBranchId(branchId);
$rootScope.passBranchId = branchId;
window.location.href="./branch?
branchId='+$rootScope.passBranchId";//Here I am redirecting to branch page with id.//
}
}
The branch page is in branchApp.js and above code is in collegeApp.js.
Now in BranchController.js I am trying to catch branchId sent from previous page.
BranchController.js
var BranchController = function($scope, $rootScope, $http, $location, $route,BranchService,$routeParams)
{
$scope.branchId = $rootScope.passBranchId;//Here i am trying to get branchId//
console.log($scope.branchId);//I am getting undefined.
}
I tried $rootScope,$routeParams.But none of them worked.
Is there any possible way that i can pass branchId from collegeApp to branchApp? or am i missing something?
When redirecting your page use $location.path('/branch/' + branchId)
Plus you already have $location in your controller.
Then you'll want to use $routeParams to find the id in your url.
Update route config to find params, should look like this
$routeProvider
...
.when('branch/:branchId', {
templateUrl: 'views/branches.html',
controller: 'BranchController'
})
Then get the value like so
$scope.branchId = $routeParams.branchId;
I realized that you wanted to share information between multiple modules within the same application. Here is a completed code sample to test the scenario.
/**
* Service definition which holds the passed values
*/
angular.module('myapp')
.config('collegeService', collegeService);
collegeService.$inject = [];
function collegeService() {
var branchId = null;
return {
getBranchId: getBranchId,
setBranchId: setBranchId
};
function getBranchId() {
/**
* Implement a promise based approach if the branch ID reads from an external source
* else just return it as given below
*/
return branchId;
}
function setBranchId(brId) {
branchId = brId
}
}
/**
* First controller definition
*/
angular.module('myapp')
.controller('CollegeController', CollegeController);
CollegeController.$inject = ['$scope', 'collegeService'];
function CollegeController($scope, collegeService) {
$scope.getBranchId = function() {
/**
* Use promise based approach as below if the read method returns a promise
*/
collegeService.getBranchId().then(function(response) {
$scope.branchId = response.data;
});
/**
* Uses a simple approach as below if the read method returns the value
*/
// $scope.branchId = collegeService.getBranchId();
};
$scope.setBranchId = function(branchId) {
CollegeService.setBranchId(branchId);
}
}
/**
* Second controller definition
*/
angular.module('myapp')
.controller('BranchController', BranchController);
BranchController.$inject = ['$scope', 'collegeService'];
function BranchController($scope, collegeService) {
$scope.init = function() {
$scope.branchId = collegeService.getBranchId();
};
/**
* Invokes the init method during the Controller getting instantiated
*/
$scope.init();
}
I finally found the solution.I just added this line and it worked.
Inside SchoolController.js
$scope.setBranchId=function(branchId)
{
window.localStorage.setItem("branchId", branchId);
}
And in BranchController.js
$scope.branchId = window.localStorage.getItem("branchId");
Now i am able to use Id anywhere in controller and also i am able to pass Id from collegeApp.js to branchApp.js ng-apps.
So I have Googled this quite allot today, and I'm afraid the answers I got, did not satisfy the problem I'm facing. I'm trying to call a method within a controller (controller as syntax) by only using a string value.
I tried window['someFunctionName'](); as well as this['someFunctionName'](); and vm['someFunctionName'](), but non of them seems to work. I'm guessing it's because the function I'm calling is not in a global space, but rather local to the controller - example:
/* #ngInject */
function dashboardController(logger, _, moment) {
var vm = this;
vm.foo = foo
function getSomeData() {
// do something....
}
function foo() {
window['getSomeData']();
this['getSomeData']();
vm['getSomeData']();
}
}
It feels so trivial ... I could do this soooooo easily in C#, but struggling with something that feels so silly!
Any advice?
Thanks!
If you don't want your function to be accessible from your template, you can still create a kind of container for your functions :
var functionContainer = {};
functionContainer.getSomeData = function() {
// Do some stuff
}
Going further, your "get data" function should be in a service that you will inject into your controller.
angular.module('myApp').factory('getDataService', function(){
return {
'getSomeData': getSomeData,
'getOtherData': getOtherData
};
function getSomeData() {
// do some stuff
}
function getOtherData() {
// do other stuff
}
});
/* #ngInject */
function dashboardController(logger, _, moment, getDataService) {
var vm = this;
vm.foo = function () {
getDataService['getSomeData']();
};
}
Can you try
/* #ngInject */
function dashboardController(logger, _, moment) {
var vm = this;
vm.foo = foo
vm.getSomeData = function() {
// do something....
}
function foo() {
vm.getSomeData();
}
}
Just simply call getSomeData(); from foo.
Like:
function foo() {
getSomeData();
}
See this fiddle
I am going through a series o documentation to understand services and factories.
Came across this working code.
var app = angular.module('plunker', []);
app.value('cnt', 7);
app.service('foo', function(cnt) {
this.cnt = ++cnt;
this.inc = function(quan) {
this.cnt += quan;
};
});
app.controller('MainCtrl', function($scope, cnt, foo) {
$scope.cnt = cnt;
$scope.foo = foo;
$scope.inc = function() {
$scope.foo.inc(1); // why $scope used here
};
});
app.controller('TangentCtrl', function($scope, foo) {
$scope.jump = function() {
foo.inc(5); // Why $scope not used here and why it doesnot work when I add scope
};
});
In TangentCtrl controller $scope.jump function its not using $scope to access foo.inc as you can see in the code I have commented.
I think there is some concept here that I dont understand , can anyone enlighten me to this.
var app = angular.module("myApp",[]);
function constructorFunction() {
this.getData = function() {
//bussiness logic
};
}
/*
* your are registering service called myService
* service/factory uses singleton design pattern
* i.e. you have an object called myService in app
*/
app.service('myService', constructorFunction);
/*
* Here, you are passing sevice name (myService) and
* constructor Function (constructorFunction) to service
* provider
* which creates singleton object (myService)
*/
/*
* angular uses injector to resolve dependencies
* your are actully tells injector to
* add these dependencies to your controller function
*/
app.controller('myCtrl',function($scope, myService){
/*
* Here, you get $scope and myService
* $scope and myService these are two different objects.
* It is not yet compulsory to inject $scope if you
* use controllerAs syntax, good practice
*/
//view specific logic
});
/*
* Note: array syntax is useful in case of minification
* ['$scope', 'foo', function($scope, foo){}]
* angular maps minified variables with strings provided
* to resolve dependencies.
*/
That is because you have injected foo while declaring the controller
app.controller('TangentCtrl', function($scope, foo) {...}
In the controller function, you get instance of the foo service.
Ideally you should write the controller as below. So when you get instance of the service within controller itself, why you need $scope to access the inc function?
app.controller('TangentCtrl', ['$scope', 'foo', function($scope, foo) {
....
}]);
Look this code
app.service('foo', function(cnt) {
this.cnt = ++cnt;
this.inc = function(quan) {
this.cnt += quan;
};
});
Image you have a class 'foo', in this class 'inc' is a function, you are exporting 'foo' as a service, in the above 'foo' can be used as a connection between two controllers to pass some data between them.
So you are just Injecting foo in 'TangentCtrl' via this line
app.controller('TangentCtrl', function($scope, foo) { ...... });
So since you can use 'foo' without $scope in front them, so foo.inc(5); will call the method inc inside foo service and thus foo can be called by other controllers to get the value.
I found a very useful tutorial on creating an angular factory that takes parameters. However useful, there's a hiccup.
Below, the factory creates an instance of a function-object/constructor. The author of the tutorial does not explain where the this "Inventory" constructor should be placed.
Would the "Inventory" constructor go into a separate file, say as an module/IFFE?
/* WHERE DOES THIS INVENTORY OBJECT GO?? */
function Inventory($http, url, project_id) {
/** The public method for getting the project price **/
this.price = function(callback) {
$http.get(url+"?project="+project_id)
.success(function(value) {
callback(value);
});
};
};
angular.factory('InventoryFactory',[
'$http',
/** This is the factory method that Angular will execute only ONCE **/
function InventoryFactory($http) {
/** This is the function that will be injected into the directive, and called multiple times by the programmer **/
return function(url, product_id) {
/** this is the new object that will be created and used by the programmer **/
return new Inventory($http, url, product_id);
};
}]);
angular.directive('inventoryStatus',['InventoryFactory',function(InventoryFactory) {
return {
link: function($scope,$el,$attr) {
var inventory = InventoryFactory('/api/projects',$scope.project_id);
inventory.price(function(value){
$scope.price = value;
});
}
}
}]);
Thanks in advance!
I'm working on a project that uses IIFE, a concept that I'm still beginning to grasp. My service seems to be fine, I'm using some Jasmine to determine that it is being defined, but when I try to inject it into my controller I get this error:
Unknown provider: StudentsServiceProvider <- StudentsService <- StudentsController
here is the controller in question:
(function() {
'use strict';
angular
.module('ngInterview.students')
.controller('StudentsController', StudentsController);
StudentsController.$inject = ['StudentsService'];
function StudentsController(StudentsService) {
/**
* Model
*/
var vm = this;
/**
* Initialization
*/
activate();
/**
* Implementations
*/
function activate() {
// Initialization code goes here
vm.students = StudentsService.getStudents();
}
}
})();
And here is the service, just in case I messed up in there somehow:
(function() {
'use strict';
angular
.module('ngInterview.api.students')
.service('StudentsService', StudentsService);
StudentsService.$inject = ['$http'];
function StudentsService($http) {
/**
* Exposed functions
*/
this.getName = getName; // This function serves no purpose. It's just here as an example.
this.getStudents = function() {
return $http({
url: "CUSTOM_URL_HERE",
method: "GET"
}).then(function successCallback(res) {
return res;
}, function errorCallback(res) {
return this.getStudents();
});
}
/**
* Implementations
*/
function getName() {
return 'studentsService';
}
}
})();
All of the files listed above are included in the index.html. If I take out the references to StudentsService, I get no errors and all of the files get instantiated correctly.
Since the service StudentsService is in another module, you have to inject the 'ngInterview.api.students' module in the main module, as below:
angular
.module('ngInterview.students', ['ngInterview.api.students'])