So when you define a controller in angular, you do so this way.
angular.module('AppName').controller('ControllerName', function ($scope, $location, dataService, commonMethods) {
});
How would you take this and make the same controller be used in two different apps?
angular.module('AppName1').controller('ControllerName', function ($scope, $location, dataService, commonMethods) {
});
angular.module('AppName2').controller('ControllerName', function ($scope, $location, dataService, commonMethods) {
});
Make a separate module with all of the items you share between various apps (controllers, services, etc.) and then just inject that module into any apps that require those items.
So in something like shared.js you have:
angular.module("shared")
.controller(...)
.service(...)
.constant(...)
Then make sure you load the shared.js file before your app's module file and then inject it with:
angular.module("app","shared")
This is exactly what modules are for, to make the application modular.
angular.module('some', []).controller('SomeController', ...);
...
angular.module('app1', ['some']);
...
angular.module('app2', ['some']);
If you put your services, factories, directives, etc. into SEPARATE js files, and each begin with . Then just include the .js file.
// Constants.js
.constant('Constants', {
Initialize_IntervalMilliseconds: {
defltTimeout: 50,
longTimeout: 250
}
});
// factoryGlobal.js
myTable.factory('factGlobal', function () {
return {
BaseURL: "http://localhost:6/api/",
etc = ""
};
});
You can use them for multiple modules. Quite nice
Related
I used dependency injections in my controllers as follows.
.controller('deals_list', function ($scope, global, config, services, dealService, pagination) {
Now the app was growed. Dependencies are growing too. I want limit these injections. So is there a way to limit those with global injections or something?
What kind of procedure actually should I follow?
var myApp= angular.module('myApp', []);
myApp.run(function ($rootScope, $location, $http, $timeout, YourService) {
$rootScope.MyService = YourService;
}
Used it into controller :
myApp.controller('YouCtrl', ['$scope', function ($scope) {
// scope inherits from root scope
$scope.MyService.doSomething();
}]);
What i believe you can do is to create a service that contains all the services that you want to use. The global service is like a facade into your real service.
The option then are to create on global service with all dependencies included. Or multiple facade service which group these services
app.service("Configurations",function(global,config) {
this.global=global;
this.standard=config;
});
app.service("AppServices",function(services, dealService, pagination) {
this.services=services;
// other assigments
});
Now you can inject Configurations and AppServices
This at least gives some visibility into what your controllers are dependent upon.
I have a page containing multiple containers. Each container will have its own controller but point to one factory, which handles all the logic interacting with a web service API. I would like to have a separate file for each controller BUT I want all of this inside of one module. for the life of me I cannot find how to include controllers from different files into one modules.
//file 1
MyController ....
//file 2
MyOtherController
//file 3
MyFactory
//file 4
The Module
The module would be composed of MyController, MyOtherController and MyFactory defined in three separate files. Can someone help with this or point me to a good resource? Thanks!
You can think of a module as a container for the different parts of your app – controllers, services, filters, directives, etc. To access a container just call its module name for example
//file.4
angular.module("theModule",[]);
now that you have declared main module within angular now you can access mainModule from anywhere using angular
//file 1
angular.module("theModule").controller("MyController",[function(){...}]);
//file 2
angular.module("theModule").controller("MyOtherController",[function(){...}]);
//file 3
angular.module("mainModule").factory("MyFactory",[function(){...}]);
Check out the documentation for more information.
I also suggest reading Google's style guide and conventions manual
Also read about setting up app structure for maintainability
Here is a example of an Angular module setup I am using in an app that allows a separate external file for each module type. Note that the app must load before the external files. Tested on Angular 1.4.9.
Index.html
<script src="bower_components/angular/angular.min.js"></script>
<script src="js/ng-app.js"></script>
<script src="js/ng-factories.js"></script>
<script src="js/ng-directives.js"></script>
<script src="js/ng-controllers.js"></script>
ng-app.js
var app = angular.module('myApp', [
'factories',
'directives',
'controllers'
]);
ng-controllers.js
//note: I am injecting the helloFac factory as an example
var ctrl = angular.module('controllers', []);
ctrl.controller('MyCtrl', ['$scope', 'helloFac', function($scope, helloFac) {
console.log(helloFac.sayHello('Angular developer'));
}]);
ng-directives.js
angular.module('directives',[])
.directive('test', function () {
return {
//implementation
}
})
.directive('test2', function () {
return {
//implementation
}
});
ng-factories.js
var factories = angular.module("factories", []);
factories.factory('helloFac', function() {
return {
sayHello: function(text){
return 'Hello ' + text;
}
}
});
I´m trying to code a CRUD app with Angular.JS, and I need your help to move on.
This is the scenario:
View 1 (index) gets JSONP data from a remote API and stores it.
View 2 (master) shows data filtered on a grid
View 3 (detail) shows an specific item selected on View 2
I did it already, but requesting the very same JSON object on each view, , but I think one only api call is enough.
I can´t figure out how to properly share this JSON object for all the controllers. I tried several tutorials on ngResource, $http, factories and services but still have not a clear path to go through.
How can I do this?
Any snippet or code sample you may share will be very useful to keep on tryin this thing...
Thanks in advance,
Ariel
You can implement a base controller to store common functionality that's shared between the controllers. I wrote a blog post about it recently, here's the code snippet showing how it works:
'use strict';
angular.module('Diary')
// base controller containing common functions for add/edit controllers
.controller('Diary.BaseAddEditController',
['$scope', 'DiaryService',
function ($scope, DiaryService) {
$scope.diaryEntry = {};
$scope.saveDiaryEntry = function () {
DiaryService.SaveDiaryEntry($scope.diaryEntry);
};
// add any other shared functionality here.
}])
.controller('Diary.AddDiaryController',
['$scope', '$controller',
function ($scope, $controller) {
// instantiate base controller
$controller('Diary.BaseAddEditController', { $scope: $scope });
}])
.controller('Diary.EditDiaryController',
['$scope', '$routeParams', 'DiaryService', '$controller',
function ($scope, $routeParams, DiaryService, $controller) {
// instantiate base controller
$controller('Diary.BaseAddEditController', { $scope: $scope });
DiaryService.GetDiaryEntry($routeParams.id).success(function (data) {
$scope.diaryEntry = data;
});
}]);
Using services to cache and share the data across controllers would be the way to go. Since services in angular are singleton, the same copy of data can be shared. A service such as
angular.module('myApp').factory('dataService', function($q, $resource) {
var items=[];
var service={};
service.getItems=function() {
var itemsDefer=$q.defer();
if(items.length >0)
itemsDefer.resolve(data);
else
{
$resource(url).query({},function(data) {
items=data;
itemsDefer.resolve(data)
});
}
return itemsDefer.promise;
}
return service;
});
Now in the controller you can inject the dataService and call the getItems method. This method returns a promise, which is either resolved using the cached data or by making remote request.
And the controller code would look something like
angular.module('myApp').controller('MyCtrl', function($scope,dataService) {
dataService.getItems().then(function(items) {
$scope.items=items;
}
});
I'm trying to define a service with methods that I can call from a module in AngularJS.
This is my first attempt at using AngularJS.
Maybe this isn't a good way to do it, but I thought that I could put some helper methods into a service that could be then reusable.
But I'm finding that the UrlHelperService isn't available from the module.
I've tried to simplify and extract just the skeleton of the three files being used:
app.js
angular.module('myApp', ['ngRoute', 'myMod', 'UrlHelperService']);
urls.js
var serv = angular.module('UrlHelperService', []);
serv.service( "UrlHelperService",
function aaMethod( ) {
this.urlHelp = function( url, aa ) {
return url;
}
}
);
module.js
var module = angular.module( "myMod", [] );
module.factory(
"myMod",
[ "$http", "$q", "UrlHelperService",
function myModFactory( $http, $q, UrlHelperService) {
// UrlHelperService isn't available here. Why?
return;
}]);
Well, if you want to use UrlHelperService with myMod you need to declare it as a dependency in myMod (as you do in myApp).
var module = angular.module( "myMod", [
"UrlHelperService"
]);
module.factory(
"myMod", [
"$http",
"$q",
"UrlHelperService",
function myModFactory( $http, $q, UrlHelperService) {
// UrlHelperService isn't available here. Why?
return;
}
]);
But it could possibly be even simpler. You are creating a myMod module and a myMod service (.factory is similar to .service), why?
Anyway, you're absolutely right to putting these helper function in a service you can reuse. It doesn't have top be on its own module though. Perhaps a simpler approach would be good enough. For example:
angular
.module('myApp', [
'ngRoute'
])
.factory('UrlHelperService', [
function UrlHelperService() {
return {
urlHelp: function(url, aa) {
return url;
}
};
}
]);
Here you have your app (its own module) and a service available to everyone else inside myApp. Sometime a separate module for some services etc is better, sometimes a service inside your main module is good enough.
EDIT: I have managed to get my unit tests running - I moved the code containing the services to a different file and a different module, made this new module a requirement for fooBar module, and then before each "it" block is called, introduced the code beforeEach(module(<new_service_module_name)). However, my application still won't run. No errors in console either. This is the only issue that remains - that when I use global scope for controllers definition, the application works, but when I use angular.module.controller - it does not.
I have a file app.js that contains the following:
'use strict';
var app = angular.module('fooBar', []);
app.config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/', {
templateUrl: 'partials/form-view.html',
controller: FormViewCtrl
}).
when('/resultDisplay', {
templateUrl: 'partials/table-view.html',
controller: TableViewCtrl
}).
otherwise({redirectTo: '/'});
}]);
app.service('searchResults', function() {
var results = {};
return {
getResults: function() {
return results;
},
setResults: function(resultData) {
results = resultData;
}
};
});
I have another file controllers.js that contains the following:
'use strict';
var app = angular.module('fooBar', []);
app.controller('FormViewCtrl', ['$scope', '$location', '$http', 'searchResults',
function ($scope, $location, $http, searchResults) {
//Controller code
}]);
searchResults is a service that I created that simply has getter and setter methods. The controller above uses the setter method, hence the service is injected into it.
As a result, my application just does not run! If I change the controller code to be global like this:
function ($scope, $location, $http, searchResults) {
//Controller code
}
then the application works!
Also, if I use the global scope, then the following unit test case works:
'use strict';
/*jasmine specs for controllers go here*/
describe('Foo Bar', function() {
describe('FormViewCtrl', function() {
var scope, ctrl;
beforeEach(module('fooBar'));
beforeEach(inject(function($rootScope, $controller) {
scope = $rootScope.$new();
ctrl = $controller('FormViewCtrl', {$scope: scope});
}));
}
//"it" blocks
}
If I revert to the module scope, I get the error -
Error: Unknown provider: searchResultsProvider <- searchResults
Thus, by using global scope my application and unit tests run but by using app.controller, they seem to break.
Another point that I have noted is that if I include the controller code in app.js instead of controllers.js, then the application and unit tests start working again. But I cannot include them in the same file - how do I get this to run in the angular scope without breaking the application and unit tests?
You don't need to go that route. You can use the modular approach, but the issue is with your second parameter.
In your app.js you have this:
var app = angular.module('fooBar', []);
Then in your controller, you have this:
var app = angular.module('fooBar', []);
What you're doing there is defining the module twice. If you're simply trying to attach to the app module, you cannot pass in the second parameter (the empty array: []), as this creates a brand new module, overwriting the first.
Here is how I do it (based on this article for architecting large AngularJS apps.
app.js:
angular.module('fooBar',['fooBar.controllers', 'fooBar.services']);
angular.module('fooBar.controllers',[]);
angular.module('fooBar.services', []);
...etc
controllers.js
angular.module('foobar.controllers') // notice the lack of second parameter
.controller('FormViewCtrl', function($scope) {
//controller stuffs
});
Or, for very large projects, the recommendation is NOT to group your top-level modules by type (directives, filters, services, controllers), but instead by features (including all of your partials... the reason for this is total modularity - you can create a new module, with the same name, new partials & code, drop it in to your project as a replacement, and it will simiply work), e.g.
app.js
angular.module('fooBar',['fooBar.formView', 'fooBar.otherView']);
angular.module('fooBar.formView',[]);
angular.module('fooBar.otherView', []);
...etc
and then in a formView folder hanging off web root, you THEN separate out your files based on type, such as:
formView.directives
formView.controllers
formView.services
formView.filters
And then, in each of those files, you open with:
angular.module('formView')
.controller('formViewCtrl', function($scope) {
angular.module('formView')
.factory('Service', function() {
etc etc
HTH
Ok - I finally figured it out. Basically, if you wish to use the module scope and not the global scope, then we need to do the following (if you have a setup like app.js and controllers.js):
In app.js, define the module scope:
var myApp = angular.module(<module_name>, [<dependencies>]);
In controllers.js, do not define myApp again - instead, use it directly like:
myApp.controller(..);
That did the trick - my application and unit tests are now working correctly!
It is best practice to have only one global variable, your app and attach all the needed module functionality to that so your app is initiated with
var app = angular.module('app',[ /* Dependencies */ ]);
in your controller.js you have initiated it again into a new variable, losing all the services and config you had attached to it before, only initiate your app variable once, doing it again is making you lose the service you attached to it
and then to add a service (Factory version)
app.factory('NewLogic',[ /* Dependencies */ , function( /* Dependencies */ ) {
return {
function1: function(){
/* function1 code */
}
}
}]);
for a controller
app.controller('NewController',[ '$scope' /* Dependencies */ , function( $scope /* Dependencies */ ) {
$scope.function1 = function(){
/* function1 code */
};
}
}]);
and for directives and config is similar too where you create your one app module and attach all the needed controllers, directives and services to it but all contained within the parent app module variable.
I have read time and time again that for javascript it is best practice to only ever have one global variable so angularjs architecture really fills that requirement nicely,
Oh and the array wrapper for dependencies is not actually needed but will create a mess of global variables and break app completely if you want to minify your JS so good idea to always stick to the best practice and not do work arounds to get thing to work
In my case, I've defined a new provider, say, xyz
angular.module('test')
.provider('xyz', function () {
....
});
When you were to config the above provider, you've inject it with 'Provider' string appended.
Ex:
angular.module('App', ['test'])
.config(function (xyzProvider) {
// do something with xyzProvider....
});
If you inject the above provider without the 'Provider' string, you'll get the similar error in OP.