I have three different application files (in addition to vendor files) for my angular app loaded in this order
app.js
store.js
controller.js
The code from the different files is only visible to the others if I'm using a global variable, however, I thought if I used modules by starting each file like this
angular.module('myApp',
then I could avoid a global and have code defined in each file available to the others.
Example
if I do it this way with the global variable myApp then the storage provider is available in the controller.
var myApp = angular.module('myApp', ['LocalStorageModule'])
.config(['localStorageServiceProvider',
function(localStorageServiceProvider) {
localStorageServiceProvider.setPrefix('my-app');
}]);
myApp.factory('myStorage',
//code ommitted
myApp.controller('MyCtrl', [$scope, 'myStorage',
function MyController($scope, myStorage){
}
]);
However, if in the three files, I instead do it this way (without the global) then I get an unknownProvider error in myCtrl
angular.module('myApp', ['LocalStorageModule'])
.config(['localStorageServiceProvider',
function(localStorageServiceProvider) {
localStorageServiceProvider.setPrefix('my-app');
}]);
angular.module('myApp', [])
.factory('myStorage',
//code omitted
angular.module('myApp', [])
.controller('MyCtrl', [$scope, 'myStorage',
function MyController($scope, myStorage){
}
]);
Question: IN the example above, how can I make the storage from the factory available in the controller without using the global variable pattern?
You should only define module once, and use it in rest of the places. Otherwise it gets overwritten. Please remove the dependency array from module definition for factory & controller. Hope that helps.
angular.module('myApp')
.factory('myStorage',
//code omitted
angular.module('myApp')
.controller('MyCtrl', ['$scope', 'myStorage',
function ($scope, myStorage){
}
]);
Also your controller declaration is needs to be corrected as above.
The Best way to inject any service, factory etc... this way reduce Complicity...
`angular.module('myApp')
.factory('myStorage',
//code omitted
angular.module('myApp')
.controller('MyCtrl', myCtrlFun);
myCtrlFun.$inject = ['$scope', 'myStorage'];
function myCtrlFun($scope, myStorage){
}
`
Related
I currently have 3 angularjs modules, each of which are (roughly) like so:
(function () {
var generalApp = angular.module('general-app', []);
generalApp.controller("NewsletterSignup.Controller", ["$scope", "$http", NewsletterSignupControllerFunction]);
}());
where NewsletterSignupControllerFunction is a global variable that is a reference to a function, eg:
var NewsletterSignupControllerFunction = function ($scope, $http) { ... };
Rather than use a global variable to share logic between the three modules, what is the simplest way to inject NewsletterSignupControllerFunction into each of the modules so I can use it to create the controllers? I have tried various approaches, none of which I can get to work.
One approach is to define a common module with the controller:
common.js
(function () {
angular.module('common', [])
.controller("NewsletterSignup.Controller",
["$scope", "$http", NewsletterSignupControllerFunction]
)
function NewsletterSignupControllerFunction ($scope,$http) {
//code ...
}
}());
Use that common module as a dependency:
angular.module("myApp",['common'])
For more information, see
AngularJS angular.module API Reference
I'm trying to inject my factory into my controller and I'm getting this error from AngularJS:
Error: $injector:unpr Unknown Provider
I have looked through almost all of the questions on here and still cannot find a solution to my problem. I believe my controller and factory and declared correctly and the injection is correct but it looks like this isn't the case.
My factory code is as follows:
var app = angular.module('test', []);
app.factory('processingFactory', function () {
var factory = {};
factory.newTest = function() {
console.log("TEST");
}
return factory;
});
This is then injected into the controller which looks like this:
angular.module("test", ["angularModalService", "anguFixedHeaderTable",
'angular-loading-bar', "ngResource", "agGrid",
'ui.tree']).controller("dashboardController", [
"$scope",
"$timeout",
"$http",
"$window",
"$interval",
"$resource",
"ModalService",
"$filter",
'$q',
'processingFactory',
function($scope, $timeout, $http, $window, $interval, $resource,
ModalService, $filter, $q, processingFactory) {
//other code removed
$scope.newWorkorder = processingFactory.newWorkorder;
}
]);
This function is called through a button click on the web page. All of the files needed are in script tags on this html page. I am fairly new to angular so this could be a simple error or something I am not aware of.
Calling angular.module with an array as the second argument declares a module, which can only happen for any given module name. You are declaring the module twice (once in your controller code, and again in your factory code).
Try changing the first part of your factory code to:
var app = angular.module('test');
If you are doing the same thing elsewhere in the app you will need to remove the second argument there too, so that there is only one module declaration in the whole app.
if there are any dependencies for your module "test" why do not you have them declared in the first line itself like:
var app = angular.module("test", ["angularModalService", "anguFixedHeaderTable",
'angular-loading-bar', "ngResource", "agGrid",
'ui.tree']);
Then declare your controller like::
app.controler(...)
Things should work fine.
I'm getting an error when running my app: Argument 'AppCtrl' is not a function, got undefined - I believe it has something to do with the separation of controller files?
Ok, so I have in my first file: app.js this:
angular.module('zerochili', [
'ionic',
'zerochili.controllers',
'zerochili.services',
'zerochili.directives'
])
Then I have some different controller files - Lets take the file there the AppCtrl is - This looks like the following:
angular.module('zerochili.controllers', [])
.controller('AppCtrl', ['$scope', '$ionicModal', '$timeout', function ($scope, $ionicModal, $timeout){
}])
And another file fx like so:
angular.module('zerochili.controllers', [])
.controller('LoginCtrl', ['$scope', '$state', '$ionicPopup', '$timeout', function($scope, $state, $ionicPopup, $timeout){
}]);
What am I doing wrong? Can't seem to quite figure it out?
You can think of your app.js as the part where you define the module. The controller files should be adding to the module (not have ", []" as this creates the module).
You should probably be doing this in your controllers
angular.module('zerochili')
.controller('AppCtrl', etc.
So, remove these: 'zerochili.controllers', 'zerochili.services', 'zerochili.directives' from the app.js and add your controllers,services and directives to the 'zerochili' module like above.
If you want to keep, for example, 'zerochili.controllers' make sure that you don't create this module twice, i.e. have angular.module('zerochili.controllers', []) twice.
It's only because you are creating a new modul with []
you can put at the end of your app.js
angular.module('zerochili.controllers', []);
angular.module('zerochili.directives', []);
angular.module('zerochili.services', []);
and then use it like this:
angular.module('zerochili.controllers')...
I'm following the AngularJS tutorial on its site, and at the moment my controller is as followed, and the page loads perfectly:
var phonecatApp = angular.module('phonecatApp', []);
phonecatApp.controller('PhoneListCtrl', function($scope, $http) {
$http.get('phones/phones.json').success(function(data) {
$scope.phones = data;
});
$scope.orderProp = 'age';
});
As I was doing the "A Note on Minification" part of Step 5, I came up with this:
var phonecatApp = angular.module('phonecatApp', []);
function PhoneListCtrl($scope, $http) {
$http.get('phones/phones.json').success(function(data) {
$scope.phones = data;
});
$scope.orderProp = 'age';
}
//phonecatApp.controller('PhoneListCtrl', ['$scope', '$http', PhoneListCtrl]);
The page loads just fine with the second code, where I commented the creation of controller from the module. My question is, what's the difference between declaring a controller from the module and defining a function
There is no difference in the actual execution/behaviour, the second one is using something called a 'function constructor'. It is a common way of creating a class-like structure in javascript.
The first one under the hood will be doing the same thing it's just that angularJs' dependency injection model works with strings so this is easier to read.
Declaring a global function, AFAIK was possible in order to simplify simple demos and get up to speed quickly. In latest versions of Angular, it's not supported by default anymore (see https://github.com/angular/angular.js/commit/3f2232b5a181512fac23775b1df4a6ebda67d018).
It's bad practice anyway to pollute the global namespace with lots of functions.
Check out Todd Motto's style guide for angular: http://toddmotto.com/opinionated-angular-js-styleguide-for-teams/
Defining your controllers as a function expressions is important to keep your code DRY and allow for named stack traces:
This is okay:
function PhoneListCtrl($scope, $http) {
$http.get('phones/phones.json').success(function(data) {
$scope.phones = data;
});
$scope.orderProp = 'age';
}
The issue is that this puts the function in the global scope; ohhh nooo. The solution is to wrap the declaration in an IIFE. This allows you to keep the best practice of defining your functions and to not pollute the global scope.
Here's an example:
(function () {
angular.module('app', []);
// MainCtrl.js
function MainCtrl () {
}
angular
.module('app')
.controller('MainCtrl', MainCtrl);
// AnotherCtrl.js
function AnotherCtrl () {
}
angular
.module('app')
.controller('AnotherCtrl', AnotherCtrl);
// and so on...
})();
Like this:
function PhoneListCtrl($scope, $http) {
your function would be declared in the global scope.
And we know that is clearly bad to pollute the global scope since it may lead to variable/function conflict.
By wrapping it inside a controller, you isolate the scope.
I have looked at various examples of separating the files. I can understand them but the problem comes with the way my code is. I want separate these controllers in different files.
'use strict';
angular.module('myModule', ['ui.bootstrap']);
var myApp = angular.module('myApp', []);
myApp.config(['$httpProvider', function ($httpProvider) {
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
}]);
myApp.config(['$routeProvider',
function ($routeProvider) {
$routeProvider.when('/getplaces', {
templateUrl: 'templates/getplaces.html',
controller: 'ListCtrl'
})
The below controller needs to be in a different file.
///////////// MONTHLY DATA /////////////////////////////////////
myApp.config(['$routeProvider', function ($routeProvider) {
$routeProvider.when('/getmonth', {
templateUrl: 'templates/getmacs.html',
controller: 'MonthlyCtrl'
})
}])
.controller('MonthlyCtrl', function ($scope, $http) { $scope.visible = true;
})
I have more than 20 controllers like above. but how do I separate them.
Here is how you should do it,
first declaration
angular.module('appName', ['Module1', 'Module2', 'Service1']);
subsequent declarations
here all the controllers and service can be in separate files.
angular
.module('Module1', [])
.controller('AbcController', ['$scope', '$timeout', 'Service1', function ($scope, $timeout, service1) {} ]);
angular
.module('Module2', [])
.controller('EfgController', ['$scope', '$timeout', 'Service1', function ($scope, $timeout, service1) {} ]);
angular.module('Service1', [])
.service('XYZService', ['$http', function LmnoService($http) {
} ]);
This should easily be done, I would organize my application route configurations into the main app.js file.
myApp.config(['$routeProvider',
function ($routeProvider) {
$routeProvider.when('/getplaces', {
templateUrl: 'templates/getplaces.html',
controller: 'ListCtrl'
}).when('/getmonth', {
templateUrl: 'templates/getmacs.html',
controller: 'MonthlyCtrl'
})
}])
Then when you create a separate controller in each file just reference the application name as such:
myApp.controller('MonthlyCtrl', ['$scope', '$http', function ($scope, $http) {
$scope.visible = true;
}])
You will also notice I am using the array initializer way, this will save you some hastles when you are doing minification.
You can follow this convention:
First load all the library dependencies like angular, angular-routes etc
then your config holder js file which contains your module declaration.
then all other files with controller methods.
I would map specific modules to functionality (and not by layers), each one containing its concerned controllers, services and appropriate directives.
You would have one module called 'places.list' for instance, containing all controllers, services/factories and directives associated to it.
The rule is: one module, one file, otherwise you would be forced to declare those files in order... (first modules declaration..then controllers etc.. ugly)
If you split your modules in the right way, you will notice that each one is easy to maintain and doesn't contain in general a huge amount of code.
Even each route declaration (.config) would be split across those modules.
=> All the route concerning places would be declared inside the module places.list.
Indeed, it would be ugly (and difficult to maintain) to declare the whole navigation rules in your main module..
Thus, each module would be easily testable by loading only specific module's dependencies that are relevant for the test.