Angular getting unknown provider error when injecting service into controller - angularjs

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'])

Related

Passing id from one controller to another of different ng-app files

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.

Angular-translate : How can I refresh content (api request) when I change language?

I'm new in AngularJS and I try to understand how to use it. I'm using angular-translate to translate my website and it works but I have a problem with the dynamic content from the database.
I get the dynamic content by an api request. I would like to "redo" the request with the good language to get the content reloaded in the good language.
I catch the "translateChangeSuccess" event but how can I "redo" the previous api request ?
Thank you very much for your help :)
ps : sorry for my english
Edit :
// my run block :
(function ()
{
'use strict';
angular
.module('fuse')
.run(runBlock);
function runBlock($rootScope, $timeout, $state, $cookieStore)
{
$rootScope.$on('$translateChangeSuccess', function () {
// catch translateChangeSuccess event
// redo the previous api request
});
}
})();
// my change language function
/**
* Change Language
*/
function changeLanguage(lang)
{
angular.forEach(vm.languages, function(value, key) {
if (lang.code == key)
$translate.use(lang.code); // launch translateChangeSuccess event
});
}
// my api service
function apiService($http, $resource, $translate, CONFIG_API)
{
// change header with good language
$http.defaults.headers.common["Accept-Language"] = $translate.proposedLanguage();
var api = {};
// Base Url
api.baseUrl = CONFIG_API.base_url;
// request to reload when user changes language
api.Documents = $resource(api.baseUrl + 'documents/:id',
{id: '#id'},
{update: {method: 'PUT'}}
);
...
}
On the translateChangeSuccess event do the request again with the current parameter for the desired language (implying that the server sends you different content depending on language)
I cannot give you a solid example since there are so many ways to manage it.
With some code you can have a better explanation.
Ok, so I found how to do that. I just ask data to the api again through a service (apiResolver)
test.module.js :
(function ()
{
'use strict';
angular
.module('app.test_module', [])
.config(config);
/** #ngInject */
function config($stateProvider, msApiProvider)
{
// State
$stateProvider.state('app.test_module', {
url : '/myurl',
views : {
'content#app': {
templateUrl: 'mytemplate.html',
controller : 'MyController as vm'
}
},
resolve : {
test : function (apiResolver)
{
return apiResolver.resolve('myquery#query');
}
}
});
}
})();
and test.controller.js :
(function ()
{
'use strict';
angular
.module('app.test_module')
.controller('testController', testController);
/** #ngInject */
function testController($rootScope, apiResolver, dataToDisplay)
{
var vm = this;
// Data
vm.dataToDisplay = dataToDisplay;
$rootScope.$on('$translateChangeSuccess', function () {
// reload my content
apiResolver.resolve('myquery#query')
.then(function(result) {
vm.dataToDisplay = result;
});
});
}
// more code here but not usefull in this example
})();
There is maybe a better way but it works, my data are translated when the user changes language :)

Angular: Where would this constructor be placed?

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!

Issues injecting Angular factories and services

I don't know what it is about injecting factories, but I am having the most difficult time.
I've simulated what I'm attempting to do via this sample plunk http://plnkr.co/edit/I6MJRx?p=preview, which creates a kendo treelist - it works fine.
I have an onChange event in script.js which just writes to the console. That's also working.
My plunk loads the following:
1) Inits the app module, and creates the main controller myCtrl (script.js)
2) Injects widgetLinkingFactory int myCtrl
3) Injects MyService into widgetLinkingFactory
The order in which I load the files in index.html appears to be VERY important.
Again, the above plunk is NOT the real application. It demonstrates how I'm injecting factories and services.
My actual code is giving me grief. I'm having much trouble inject factories/services into other factories.
For example,
when debugging inside function linking() below, I can see neither 'CalculatorService' nor 'MyService' services. However, I can see the 'reportsContext' service.
(function () {
// ******************************
// Factory: 'widgetLinkingFactory'
// ******************************
'use strict';
app.factory('widgetLinkingFactory', ['reportsContext', 'MyService', linking]);
function linking(reportsContext, MyService) {
var service = {
linkCharts: linkCharts
};
return service;
function linkCharts(parId, widgets, parentWidgetData) {
// *** WHEN DEBUGGING HERE, ***
// I CANNOT SEE 'CalculatorService' AND 'MyService'
// HOWEVER I CAN SEE 'reportsContext'
if (parentWidgetData.parentObj === undefined) {
// user clicked on root node of grid/treelist
}
_.each(widgets, function (wid) {
if (wid.dataModelOptions.linkedParentWidget) {
// REFRESH HERE...
}
});
}
}
})();
A snippet of reportsContext'service :
(function () {
'use strict';
var app = angular.module('rage');
app.service('reportsContext', ['$http', reportsContext]);
function reportsContext($http) {
this.encodeRageURL = function (sourceURL) {
var encodedURL = sourceURL.replace(/ /g, "%20");
encodedURL = encodedURL.replace(/</g, "%3C");
encodedURL = encodedURL.replace(/>/g, "%3E");
return encodedURL;
}
// SAVE CHART DATA TO LOCAL CACHE
this.saveChartCategoryAxisToLocalStorage = function (data) {
window.localStorage.setItem("chartCategoryAxis", JSON.stringify(data));
}
}
})();
One other point is that in my main directive code, I can a $broadcast event which calls the WidgetLinking factory :
Notice how I'm passing in the widgetLinkingFactory in scope.$on. Is this a problem ?
// Called from my DataModel factory :
$rootScope.$broadcast('refreshLinkedWidgets', id, widgetLinkingFactory, dataModelOptions);
// Watcher setup in my directive code :
scope.$on('refreshLinkedWidgets', function (event, parentWidgetId, widgetLinkingFactory, dataModelOptions) {
widgetLinkingFactory.linkCharts(parentWidgetId, scope.widgets, dataModelOptions);
});
I am wasting a lot of time with these injections, and it's driving me crazy.
Thanks ahead of time for your assistance.
regards,
Bob
I think you might want to read up on factories/services, but the following will work:
var app = angular.module('rage')
app.factory('hi', [function(){
var service = {};
service.sayHi = function(){return 'hi'}
return service;
}];
app.factory('bye', [function(){
var service = {};
service.sayBye = function(){return 'bye'}
return service;
}];
app.factory('combine', ['hi', 'bye', function(hi, bye){
var service = {};
service.sayHi = hi.sayHi;
service.sayBye = bye.sayBye;
return service;
}];
And in controller...
app.controller('test', ['combine', function(combine){
console.log(combine.sayHi());
console.log(combine.sayBye());
}];
So it would be most helpful if you created a plunk or something where we could fork your code and test a fix. Looking over your services it doen't seem that they are returning anything. I typically set up all of my services using the "factory" method as shown below
var app = angular.module('Bret.ApiM', ['ngRoute', 'angularFileUpload']);
app.factory('Bret.Api', ['$http', function ($http: ng.IHttpService) {
var adminService = new Bret.Api($http);
return adminService;
}]);
As you can see I give it a name and define what services it needs and then I create an object that is my service and return it to be consumed by something else. The above syntax is TypeScript which plays very nice with Angular as that is what the Angular team uses.

Using closure compiler with AngularJS

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();
}
}]);

Resources