AngularJS module dependency injection sharing its dependencies with parent module - javascript

I have an AngularJS module:
angular.module("app", ['ui.bootstrap', 'ngRoute', 'ngGridPanel']).config(function($routeProvider) {
As you can see it has ngGridPanel included via dependency injection.
Here is the definition of ngGridPanel's module/directive:
angular.module('ngGridPanel', ['ngAnimate']).directive('gridPanel', ['$animate', '$compile', '$window', '$document', '$timeout', function ($animate, $compile, $window, $document, $timeout) {
As you can see, it refers to ngAnimate.
The problem I am having is that once I inject ngGridPanel into my app, every element in my app is suddenly attempting to be animated.
Now, as described in this Angular.js GitHub issue, ngAnimate will assume everything should be animated. Once I realized this is the expected behaviour, I realized that I never included ngAnimate into my app module in the first place.
So why would it be affecting my entire application? Shouldn't it only take effect in the directive that belongs to the ngGridPanel module?
So how is ngAnimate affecting the parent module scope? Is this normal?
Side-note: At this point I haven't even utilized the ngGridPanel directive at all. I have merely injected it into my app.
Side-note 2: Once I implemented a class name filter ($animateProvider.classNameFilter(/enable-animate/);) in my app, animations stopped on all my elements but remained working in the ngGridPanel directive without having to add the enable-animate class anywhere.

If you depend on ngGridPanel and ngGridPanel depends on ngAnimate, then you depend on ngAnimate as well.
It is the exact same to you as if you had defined your app with
angular.module("app", ['ui.bootstrap', 'ngRoute', 'ngGridPanel', 'ngAnimate'])
.
As for your Side-note 2, it seems likely that they have configured it to use something like .classNameFilter() as well so that animations wouldn't break if the user of their library decided to configure it differently, such as you did. I don't know too much about ngAnimate so that's just a hunch.

Related

load fabric js in angular application

So i downloaded and installed fabricjs using bower inside of my angular application and i am having trouble loading it up.
I have the following on top of my app.js file. Everything else loads fine except fabric
angular
.module('myApp', [
'flow',
'fabric',
'ngAnimate',
'ngCookies',
'ngResource',
'ngRoute',
'ngSanitize',
'ngTouch',
'ui.bootstrap',
'ui.router',
'controllers.main',
])
.config( function ($stateProvider, $httpProvider, flowFactoryProvider ) {
When i load the page i get the following error.
[$injector:modulerr] Failed to instantiate module fabric due to: [$injector:nomod] Module 'fabric' is not available! You either misspelled the module name or forgot to load it.
I am loading it up in my index.html
<script src="bower_components/fabric/dist/fabric.min.js"></script>
Anyone have any success with loading fabric inside of their angular application?
Even though this is old, I'll try to answer it for future searchers.
I've been using Fabric inside Angular with great success.
From what I can see in your code example, you are attempting to use the standard fabic.min.js file as a Angular Module. Angular only sees it as pure JS, that is why it generates an error saying it couldn't find it - because no Angular module called "fabric" was ever declared like:
angular.module('fabric', []);
If you compare one of the other modules you had listed, say ngCookies, you can see how one is setup.
It would be too much code to post here, so the easiest solution is to utilize or study some of the excellent work by Michael Calkins here:
https://github.com/michaeljcalkins/angular-fabric
He has everything wrapped up in directives and such which makes it easy to implement.
You can also play around with it live here: http://codepen.io/michaeljcalkins/pen/Imupw
Hope that helps someone.

Why can't AngularJS resolve this dependency

MyApp.js:
'use strict';
angular.module('MyApp', [
'ngRoute',
'MyApp.components.hello',
'MyApp.pages.index',
'MyApp.pages.upload'
]).
config(['$routeProvider', 'HelloService', function($routeProvider, HelloService) {
$routeProvider.
when('/',
{
templateUrl: 'pages/index/index.html',
controller: 'IndexController'
}).
when('/upload',
{
templateUrl: 'pages/upload/upload.html',
controller: 'UploadController'
}).
otherwise({redirectTo: '/'});
HelloService.init({
facebook : ID_HERE
});
}]);
hello-service.js:
'use strict';
angular.module("MyApp.components.hello", []).
factory("HelloService", function()
{
return window.hello; //assume hello has been loaded
});
When I try to run it, I get the error Error: [$injector:unpr] Unknown provider: HelloService. Why? HelloService is clearly defined in MyApp.components.hello, which is included as a dependency of the main application. So why can't it find HelloService?
Check this article:
Understanding Dependency Injection by josepot
and this section
Configuring Providers
You may be wondering why anyone would bother to set up a full-fledged provider with the provide method if factory, value, etc. are so much easier. The answer is that providers allow a lot of configuration. We've already mentioned that when you create a service via the provider (or any of the shortcuts Angular gives you), you create a new provider that defines how that service is constructed. What I didn't mention is that these providers can be injected into config sections of your application so you can interact with them!
First, Angular runs your application in two-phases--the config and run phases. The config phase, as we've seen, is where you can set up any providers as necessary. This is also where directives, controllers, filters, and the like get set up. The run phase, as you might guess, is where Angular actually compiles your DOM and starts up your app.
So, where is the issue?
We can ask JUST for Providers to be injected into .config()
BUT - they are used in .config() just to be configured, not to be used
I don't think you can inject a service to config block.
Module Loading & Dependencies
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.
Config is too early stage to star working with services, providers and factories.
Try moving that HelloService initialization part to run, like that:
.run(['HelloService', function(HelloService) {
HelloService.init({
facebook : ID_HERE
});
}])

Cannot inject AuthenticationController

I am trying to inject a controller into my app.run function, however i keep getting:
Uncaught Error: [$injector:unpr] http://errors.angularjs.org/1.2.10/$injector/unpr?p0=AuthenticationControllerProvider%20%3C-%20AuthenticationController
Here's my app.js:
var app = angular.module('app', [
'AuthenticationModule'
]);
app.run(['$rootScope', 'AuthenticationService', 'AuthenticationController',
function($rootScope, AuthenticationService, AuthenticationController) {
console.log(AuthenticationController);
}
]);
The AuthenticationService is injecting just fine. Why are AuthenticationController not being injected?
As stated in the AngularJS documentation on modules:
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.
In the documentation for controllers, it states:
In Angular, a Controller is a JavaScript constructor function that is
used to augment the Angular Scope. When a Controller is attached to
the DOM via the ng-controller directive, Angular will instantiate a
new Controller object, using the specified Controller's constructor
function.
A controller is an instance constructor function, not an instance itself, as opposed to a service, which is. Therefor, from what I can gather, controllers cannot be injected into a run block.
If you need to configure a controller at start-up time, then use a provider. As it turns out, in angular, controllers (along with directives, filters, and animations) are all simply syntactic sugar for a provider. Providers can be configured using configuration blocks: configuration block documentation
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.

Best practices to manage dependencies in Angular JS

I really enjoy the use of AMD to manage dependencies.
Now I'm getting started with Angular, in that case things become more complicated, because in one file we refer to a certain object that we admit to have already been created and this requires to make the script tags all organized and so on.
Another thing I noticed is that as the app grows there will be many script tags and more things to grant to be in order. I found ways to make AMD work with Angular.js, but I really didn't like it because it didn't seem natural.
What are the best practices to manage dependencies in Angular JS, making it easier to maintain the app as it grows?
I'd suggest Require.js which does implement AMD. There's a great example of how to configure your main.js (the entry point for a require.js application) and test-main.js (entry point for karma tests) here: https://github.com/tnajdek/angular-requirejs-seed.
Notes:
make sure to use paths and shim for dependent modules that you want to expose to your application but that are not available as require.js modules.
make sure you keep in mind the distinction between angular.js's concept of modules and require.js modules. Require.js modules are about describing file dependencies and loading in the correct fashion. Angular modules are about enabling dependency injection, once this loading is done correctly. You'll end up with code that looks like this example:
example app.js
define([
'angular', //as defined in the requirejs shim config
'filters', //as defined in the filters.js
'services', //as defined in services.js
'directives', //in directives.js
'controllers', //in controllers.js
'angularRoute',//as defined in the requirejs config
],function(angular,filters,services,directives,controllers,angularRoute){
'use strict';
//angular.js module definition syntax: Declare app level module which depends on filters,services,controllers,directives, and angular globals
var angularappModule = angular.module('angularapp', [
'ngRoute',
'angularapp.filters',
'angularapp.services',
'angularapp.directives',
'angularapp.controllers'
]);
angularappModule.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/angularapp', {templateUrl: 'partials/angularapp.html', controller: 'angularappCtrl'});
$routeProvider.when('/view2', {templateUrl: 'partials/partial2.html', controller: 'MyCtrl2'});
$routeProvider.otherwise({redirectTo: '/angularapp'});
}]);
return angularappModule;
});

Load controller after bootstrap angularjs

I am using requirejs and angularjs to load the module inside my application.
The problem I am facing is I dont know how to load the controller after angular has been bootstrapped. Here is my code :
main.js :
require(['app', //all my scripts go here
function(){
angular.bootstrap(document, ['myApp']);
});
app.js :
define([], function(){
var myApp = angular.module('myApp', ['ngRoute']);
$routeProvider.
when('/home', {
templateUrl : 'partials/home.html',
controller : 'UserRegisterCtrl'
}).
otherwise({
redirectTo : '/home'
})
return myApp;
})
controller.js
define(['app'], function(app){
app.controller('MyCtrl', function($scope){});
})
myApp.html
body(ng-app)
<div ng-controller = 'MyCtrl'></div> <-- I can not put MyCtrl here
because I think the MyCtrl has been declared before myApp has been bootstrapped
Therefore I really need to know if there is a way to load the MyCtrl controller after myApp has been bootstrapped. I am really new to Angularjs. Any help would be really appreciate.
If you are manually bootstrapping your angular app there is no need for ng-app, because this is just a directive that pretty much does the same thing.
This little trap caused some people a headache before:
Why do I need to angular.bootstrap even when I declare ng-app="MyApp" in JSFiddle
angular bootstrapping issues angular.bootstrap not working on my apps
When you use ng-app in your html, the bootstrap happens automatically. In this case, it depends what you put in the <script> tag in your index.html.
I am assuming that you follow the RequireJS usage where you load angular using RequireJS. If so, make sure you declare the dependency of angular to your app using shim. If that is not the case, please state how your are loading angular and share the content of your main.js.
It was really tricky for me to get RequireJS to work with AngularJS so I created following project that helped me deal with the complexity:
http://marcoslin.github.io/angularAMD

Categories