AngularJS: directive/dependency injection - javascript

To add dependency to Angular, this is what docs tells to do :
Source
//inject directives and services.
var app = angular.module('fileUpload', ['ngFileUpload']);
app.controller('MyCtrl', ['$scope', 'Upload', function ($scope, Upload) {...
But can we inject directive directly into controller like this:
var app = angular.module('fileUpload', []);
app.controller('MyCtrl', ['ngFileUpload','$scope', 'Upload', function (ngFileUpload,$scope, Upload) {...
If not, what is the reason for not providing this capability to controller?
Is there a way to inject dependency when a particular controller loads?

No modules are the essentially the base or a "toolbox" if you will. You need to inject one module into another so that the it can have access to its "tools" (filters/directives/services etc). The reason is that the module is responsible for dependency loading and order of operations. This is so that when you request a "tool" from a module into a controller you can be sure it is there (or an error will be thrown).
Modules can list other modules as their dependencies. Depending on a module implies that the required module needs to be loaded before the requiring module is loaded. In other words the configuration blocks of the required modules execute before the configuration blocks of the requiring module. The same is true for the run blocks. Each module can only be loaded once, even if multiple other modules require it.
When you inject one module into another you are saying "Module A requires things from Module B". Now when you when you require a specific tool that is when you inject it into the controller so that you have access to that specific tool.
So consider:
var app = angular.module('myApp', ['ngFileUpload']);
app.controller('MyCtrl', ['$scope', 'Upload', function ($scope, Upload) {
.....
Upload.upload(uploadData).then(function (resp) {
//success
}, null, function (evt) {
//upload progress
});
.....
}]);
So because you inject ngFileUpload your controller in the myApp module can now inject the Upload service from the ngFileUpload module and the controller does not need to worry if the service is present (if it is not you will get an injection error from angular).

Related

angular js injector module error

i am new to angular js i am trying to inject factory in a config ,but it shows module not found
factory code
var app=angular.module('app',['ui.router','angular-jwt','ngResource','angularValidator','satellizer']);
app.factory('AUTH_SERVICE', function ($auth,$state,$q) {
var auth={};
auth.isloggedin=function() {
var defer = $q.defer();
if($auth.isAuthenticated()){
defer.resolve();
}
else
{
$state.go('login');
defer.reject();
}
return defer.promise;
}
return auth;
});
config code is
app.config(['AUTH_SERVICE','$authProvider','$stateProvider', '$urlRouterProvider',function(AUTH_SERVICE,$stateProvider, $urlRouterProvider,$authProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider
.state('home',{
url:'/',
templateUrl:'pages/home.html'
})
.state('login',{
url:'/login',
templateUrl:'pages/login.html',
controller:'loginCtrl'
})
.state('register',{
url:'/register',
templateUrl:'pages/register.html',
controller:'registerCtrl'
})
.state('dashboard',{
url:'/Dashboard',
templateUrl:'pages/dashboard.html',
controller:'dashctrl',
resolve:{
skiplogin: _skiplogin
}
})
function _skiplogin(AUTH_SERVICE){
return AUTH_SERVICEAUTH_SERVICE.isloggedin();
}
}]);
but it shows error
angular.js:38Uncaught Error: [$injector:modulerr]
http://errors.angularjs.org/1.5.8/$injector/modulerr?p0=app&p1=Error%3A%20%…ocalhost%2Faccoex%2Fbower_components%2Fangular%2Fangular.min.js%3A39%3A319)
You can't inject factory object in the app.config because it can't be sure they have been loaded correctly..
In the app.config you can only inject Consts and Providers.
From the documentation
A module is a collection of configuration and run blocks which get
applied to the application during the bootstrap process. In its
simplest form the module consist of collection of two kinds of blocks:
Configuration blocks - get executed during the provider registrations
and configuration phase. Only providers and constants can be injected
into configuration blocks. This is to prevent accidental instantiation
of services before they have been fully configured.
Run blocks - get executed after the injector is created and are used
to kickstart the application. Only instances and constants can be
injected into run blocks. This is to prevent further system
configuration during application run time.
Take a look to provider here where you can configure a service in your app.config.
you can't inject factory in config as it loads after config
angularjs application loads as follows:
Run
Config
Instantiate factory or service
Controller

Passing dependencies to a module angular

So I am somewhat new to angular, but not javascript. I am working with an app someone else wrote and am trying to create a new controller in an existing module. The controllers are almost identical to each other as far as dependencies go. The question I have is how do I pass the same dependencies to both controllers? It seems like you would be able to pass them in like this:
`angular.module('ApertureForm', ['dialogs.main','dialogs.default-translations','ui.bootstrap'])`
When I do that for both modules, the controller returns undefined for whatever reason. Thats where I get stuck. How do you pass in dependencies such as the above code? Any advice would be great.
angular.module('ApertureForm', ['dialogs.main','dialogs.default-translations','ui.bootstrap']) tells AngularJS to initialize an Angular module named ApertureForm and also load other Angular modules as dependencies for the module.
To add dependencies to a controller, you do something like the following:
angular.module('ApertureForm').controller('ControllerName', function($scope, $location, $timeout) {...});
angular.module('ApertureForm') = Get the module named ApertureForm.
Then create a controller called ControllerName. The closure is where you inject dependencies.
To prevent a controller's dependencies from getting renamed on minification, you can do:
angular
.module('ApertureForm')
.controller('ControllerName', ControllerName);
ControllerName.$inject = ['$scope', '$location', '$timeout'];
function ControllerName($scope, $location, $timeout) {...}
Docs: https://docs.angularjs.org/guide/di
In angular.module('ApertureForm',[ you list the modules you want to inject to your module. You list in once for each module you have. If You want to create a controller in one of your modules, then your can use:
var myApp = angular.module('ApertureForm');
myApp.controller('GreetingController', ['$scope', function($scope) {
$scope.greeting = 'Hola!';
}]);
$scope here is a dependency for controller
You can read more about it here
AngularJS Controllers and Dependency Injection:
angular
.module('ApertureForm', ['dialogs.main','dialogs.default-translations','ui.bootstrap'])
.controller('FormController', ['$scope', '$http', function($scope, $http) {
// FormController code...
}])
.controller('WebinarController', ['$scope', '$http', function($scope, $http) {
// WebinarController code...
}]);
Thanks to everyone for the help! All of it was very useful in learning the structure of angular and how to properly use the framework. #Yosvel Quintero was able to explain how the module works and why I was getting the error. When dependencies are passed into the module, not the controller, they are available to all controllers as it the module it's self is now aware of the dependencies, which is why I kept getting errors trying to pass them again. Hopefully the answers given in response to the question can help someone learn angular as well. Thanks guys!

Should AngularJS modules be in their own file?

Fairly simple question, I can't seem to find a definitive answer. At the minute I've my module declared in one file :
var module = angular.module("app", ["agGrid", "ngAnimate", "ngSanitize", "ui.bootstrap"]);
and my controller in another :
angular.module("app").controller("mainCtrl", ["$scope", "$timeout", "dateFilter", "$http", "shareDataService", "getDataService", function ($scope, $timeout, dateFilter, $http, shareDataService, getDataService) {
Is this good structure or a waste of time and space?
Single Responsibility
Define 1 component per file.
The following example defines the app module and its dependencies, defines a controller, and defines a factory all in the same file.
Avoid this
angular
.module('app', ['ngRoute'])
.controller('SomeController', SomeController)
.factory('someFactory', someFactory);
function SomeController() { }
function someFactory() { }
The same components are now separated into their own files.
Do this
// app.module.js
angular
.module('app', ['ngRoute']);
// some.controller.js
angular
.module('app')
.controller('SomeController', SomeController);
function SomeController() { }
// someFactory.js
angular
.module('app')
.factory('someFactory', someFactory);
function someFactory() { }
https://github.com/johnpapa/angular-styleguide#style-y001
It's a good practice to keep them separate. This way, you don't end up mixing the module(s) definition and controllers / services / directives.
here you get some of the best practices in angular js -
Instead of slicing your app across horizontals that can't be broken
up, group your code into related bundles. This way if you remove a
module, your app still works.
https://github.com/angular/angular.js/wiki/Best-Practices
Having separate files for each type of component is ideal. I follow the structure in development:
app.js //where the module resides
routes.js //consists of routes
controllers/
services/
factories/
filters/
directives/
Define your module:
var app = angular.module();
Then use 'app' to declare other nested js in separate files, example:
app.directive()
However, in production, it is preferable to use task runner (eg gulp) to combine all the files and minify the final file.

How to define controllers in multiple files - AngularJs

I am trying to define controllers in separate files, but I'm getting the error:
transactionsController not a function got undefined
File structure
I have added files in this sequence
1- common.js
2- transactions.js
Common.js
In common files I have defined
var app = angular.module("spModule", ["ngMessages", "ui.bootstrap"]);
Transactions.js
angular.module('spModule').controller('transactionsController',
['$scope', '$http', function ($scope, $http) {} ]
);
HTML FIle
<body ng-app="spModule" ng-controller="transactionsController">
First, you should get rid of the global app variable. This is not necessary. Second, you have to understand the principle of the angular.module() method.
Using angular.module() with two parameters (e.g. angular.module('my-module', [])) would result in setting a new module with its corresponding dependencies. In contrast, when using angular.module('my-module') the corresponding module is looked up internally and returned to the caller (getting).
The means when you first define you application you might just create the following files and structure.
app.js
angular.module('myApp', []);
FirstController.js
angular.module('myApp').controller('FirstController', function () {});
SecondController.js
angular.module('myApp').controller('SecondController', function () {});
If you now include these files in your html document in this particularly order (at least app.js has to come first), your application works just fine with two separate controllers in two separate files.
Further readings
I can recommend the AngularJS Styleguide on modules for getting more ideas on this topic.
You Can put this controller in seprate file like mycontroller1.js
app.controller('myController', ['$scope',function($scope)
{
$scope.myValue='hello World'
}])
Same like this you can create new js file 'myNewcontroller.js' and can put new controller :
app.controller('myController2', ['$scope',function($scope)
{
$scope.myValue='hello World'
}])
Hope this will help you :) Cheers !!
You can do this stuff by creating modules. Create module and respective controllers. And inject that module to the main app module.
Transactions.js
(function() {
'use strict';
angular.module('tmodule', []);
})();
(function() {
'use strict';
angular.module('tmodule').controller('transactionsController', ['$scope', '$http',
function ($scope, $http){
}]);
})();
Now inject the "tmodule" to your Common.js file-
var app = angular.module("spModule", ["ngMessages", "ui.bootstrap","tmodule"]);
Load your common.js first. Move ng-app directive to <html> tag. Change transaction.js to:
app.controller('transactionsController', TransactionsController)
TransactionsController.$inject = ['$scope','$http']
function TransactionsController($scope, $http) {
};
Just for fun. Let me know what happens.

AngularJS and Webpack Integration

I am looking for some help with using webpack for a large AngularJS application. We are using folder structure based on feature (each feature/page has a module and they have controllers, directives). I have successfully configured webpack to get it working with Grunt, which produces one single bundle. I want to create chunks as its going to be a large app, we would like to load modules (page/feature) artifacts asynchronously.
I am going through some of the webpack example to use 'code splitting' using require([deps],fn ) syntax. However I couldn't get the chunks lazy-loaded. First of all, I don't know where exactly, I would need to import these chunks before AngularJS would route the user to next page. I am struggling to find a clear separation of responsibility.
Did someone point me to an example AngularJS application where webpack is used to load controllers/directives/filters asynchronously after each route?
Few of the links I am following:
Should I use Browserify or Webpack for lazy loading of dependancies in angular 1.x
https://github.com/petehunt/webpack-howto#9-async-loading
http://dontkry.com/posts/code/single-page-modules-with-webpack.html
Sagar Ganatra wrote a helpful blog post about code splitting.
Suprisingly code splitting isn't really supported by angular's module system. However, there is a way to achieve code splitting by saving a reference to angular's special providers during the config-phase.
[...] when Angular initializes or bootstraps the application, functions - controller, service etc,. are available on the module instance. Here, we are lazy loading the components and the functions are not available at a later point; therefore we must use the various provider functions and register these components. The providers are available only in the config method and hence we will have to store a reference of these providers in the config function when the application is initialized.
window.app.config([
'$routeProvider',
'$controllerProvider',
'$compileProvider',
'$filterProvider',
'$provide',
function ($routeProvider, $controllerProvider, $compileProvider, $filterProvider, $provide) {
$routeProvider.when('/login', {
templateUrl: 'components/login/partials/login.html',
resolve: {
load: ['$q', '$rootScope', function ($q, $rootScope) {
var deferred = $q.defer();
// lazy load controllers, etc.
require ([
'components/login/controllers/loginController',
'components/login/services/loginService'
], function () {
$rootScope.$apply(function () {
deferred.resolve();
});
});
return deferred.promise;
}]
}
});
//store a reference to various provider functions
window.app.components = {
controller: $controllerProvider.register,
service: $provide.service
};
}
]);
Now inside your loginController for instance you write
app.components.controller('loginController');
to define your new controller lazily.
If you want to lazy-load your templates too I recommend to use the ui-router. There you can specify a templateProvider which is basically a function to load templates async
This is a quote from
https://github.com/webpack/webpack/issues/150
webpack is a module bundler not a javascript loader. It package files from local disk and don't load files from the web (except its own chunks).
Use a javascript loader, i. e. script.js
var $script = require("scriptjs");
$script("//ajax.googleapis.com/ajax/libs/angularjs/1.2.9/angular.min.js", function() {
// ...
});

Categories

Resources