What does module function do in AngularJS? - angularjs

In the project of Vojta about testing directives What does this code do ?
// load the tabs code
beforeEach(module('tabs'));
It says it loads the tabs code but, why ? Isn't the tabs module already defined next here ?
var tabs = angular.module('tabs', []);
Can some one give a brife explanation of what should be loaded why and how in angular test ?
I tried to call this function in my tests, like this
beforeEach(module('utils')) ;
and I get this error :
TypeError: Property 'module' of object [object Object] is not a function
Also when I try load my templates like this
beforeEach(module('templates/loadingBar.html'));
I get this error :
Error: No module: templates/loadingBar.html
I am really confused about the whole process.
Thanks for helping ...

The code you listed
var tabs = angular.module('tabs', []);
creates the tabs module, but in order to load it you probably put something like ng-app="tabs" on an element in your DOM. This instructs Angular to load the tabsmodule and make its definitions available to the injector that the app uses to resolve dependencies. (See the Bootstrap guide for more information.)
In your tests, there is no ng-app directive to initialize the injector or load your module; the module function (which exists on angular.mock from the angular-mocks.js file) does this for you in tests. If you use the Karma Jasmine or Mocha adapter for testing, it makes module available to you, otherwise you may need to call angular.mock.module instead.

Related

What is the best way to import a component from another module, in AngularJS?

I have 2 sub-modules in my AngularJS (v1.7) app, let's call them A and B. I'm trying to import a component (with html template and controller) from module B (componentB), to be used inside the template of a component in module A (componentA).
After reading Reuse AngularJS Component in another Module (Dependency Injection), I first tried to do this by specifying componentB as a dependency of componentA and then using it inside componentA's template.
componentA.js
angular.module('A', ['componentB']).component('componentA', {...});
componentA.html
<div>
<componentB></componentB>
</div>
Unfortunately this did not work, even though componentB is correctly defined and being successfully used in module B. I also tried to specify module B as a dependency of module A, by modifying app.js as shown below:
angular.module('A', ['B'])
.config(...
In both cases, I'm getting an
Uncaught Error: [$injector:modulerr]
I'm having a hard time finding similar questions/articles that relate to AngularJS as opposed to the newer Angular. I'm also pretty rusty with AngularJS so any help would be appreciated, thanks in advance.
It is pretty straight forward:
angular.module("moduleB",[])
.component("componentB", {
template: "<div>This is Component B from Module B</div>"
});
angular.module("moduleA",["moduleB"])
<div ng-app="moduleA">
<component-b></component-b>
</div>
The moduleA imports components from moduleB by declaring moduleB as a dependency.
Module Creation vs Retrieval
Only the first module declaration should have dependencies specified.
ERRONEOUS
angular.module('moduleA', [])
.controller('ctrl', /* ... */)
angular.module('moduleA', ['moduleB'])
.service('serviceA', /* ... */)
Declaring dependencies again will cause the controller to be unregistered.
Better
angular.module('moduleA', ['moduleB'])
angular.module('moduleA')
.controller('ctrl', /* ... */)
angular.module('moduleA')
.service('serviceA', /* ... */)
For more information, see
AngularJS Developer Guide - Module Creation vs Retrieval
AngularJS angular.module API Reference

Why angular.bootstrap() to document throws error

I have my test example in this plunkr link
My question is NOT DUPLICATE of this one
Also the Google Result and Github Bug was about the bug reporter not defining the module which he was trying to bootstrap in the first place
I have 3 modules grandParentModule, parentModule and nestedModule.
I have bootstrapped parentModule and nestedModule to 2 nested div elements and they are working fine.
But as soon as I try to bootstrap grandParentModule to document, it is throwing a console error.
This is my HTML
<div id="parent" ng-app="parentModule">
<div id="nested">
</div>
</div>
And this is my SCRIPT
angular.module('grandParentModule', []);
angular.module('parentModule', []);
angular.module('nestedModule', []);
var nestedElem = document.getElementById("nested");
angular.bootstrap(angular.element(nestedElem), ['nestedModule']);
//comment / uncomment this line to toggle the error at console
angular.bootstrap(document, ['grandParentModule']);
Only this line angular.bootstrap(document, ['grandParentModule']); is causing the error
Uncaught Error: [ng:btstrpd] http://errors.angularjs.org/1.5.5/ng/btstrpd?p0=%26lt%3Bdiv%20id%3D%22parent%22%20ng-app%3D%22parentModule%22%26gt%3B
Can anyone explain to me why is it happening?
This isn't how works angular bootstrapping.
You're supposed,to bootstrap only one module.
If you use multiple independant module, the DOM element where you bootstrap them must not be nested.
Furthermore what are those module supposed to be ?
If they're linked then they must have dependencies between them ie :
angular.module('parentModule', ['grandParentModule']);
If you want to have some nested views with their own controller use either multiple ng-controller or check ui-router on the net.

AngularJS loading modules

I'm having a really hard time trying to make modules working on an app I'm building.
This is the main file
main.js
'use strict';
angular.module('clientPortalPublic',[
'ngCookies',
'ngResource',
'ngAnimate',
'clientPortalPublic.components'
]);
angular.module('clientPortalPublic.components',[]);
And I have another file switch-login-effect.js
'use strict';
angular.module('clientPortalPublic.components').directive('switchLoginEffect',['$timeout', function($timeout){
//Content removed for clarification
}]);
The order that those files are being loaded is:
<script type="application/javascript" src="public/components/switch-login-effect.js"></script>
<script type="application/javascript" src="public/main.js"></script>
I know the switch-login-effect.js should be loaded later, since is requiring the main module, but it's being loaded dynamically and I don't control the order. BUT using manual bootstrapping shouldn't angular deal with it?
This is how I'm bootstrapping it
angular.element(document).ready(function() {
angular.bootstrap(document, ['clientPortalPublic']);
});
If I run the code above I get:
Error: [$injector:nomod] Module 'clientPortalPublic.components' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.
Thanks!
You are declaring a directive on a non-existant module when switch-login-effect.js loads first. It looks like you are trying to dynamically control what elements are included in the clientPortalPublic.components module simply by adding or removing scripts, but I don't think angular's dependencies are set up for that. A main reason to have those dependencies is to know exactly what you are getting.
The clientPortalPublic.components module should be defined in one script file if possible. If you have various components you can create different modules for each, but the definition of your application module should know what it is getting by the dependencies it requires. That would cause debugging headaches for one reason, "Why is my directive not working? I'm loading the components module..." (but you missed a script file you have no way to know that you need)
I really don't advise creating your app this way, but if you are dead-set you could catch the error and create the module at the start of each individual component file (and in your main.js in case you don't actually have any components but still want to require the module) so it doesn't matter which one is loaded first:
try {
angular.module('clientPortalPublic.components');
} catch (err) {
angular.module('clientPortalPublic.components',[]);
}
Or more simply just uses javascript to see if it's been executed:
var componentsModule = componentsModule ||
angular.module('clientPortalPublic.components',[]);
After reading some angular good practices and paying more attention to angular seed, I have it working.
THe thing is that they recommend to do the following when you have an structure similar to:
app/
app/components
app/components/component1
app/components/component2
app.js => angular.module('main',['main.components']);
app/components/components.js => angular.module('main.components',['main.components.component1', 'main.components.component2']);
app/components/component1.js => angular.module('main.components.component1',[]);
app/components/component2.js => angular.module('main.components.component2',[]);
Having that structure make sense and works perfectly.
:)

How to automatically load a module in AngularJS without specifying it as a dependancy

ngMock does some magic to automatically include itself if you include angular-mocks.js in your index.html.
What's the simplest way to force angular to load a module in test mode simply by including a file and not having to edit any module dependencies.
The only way to load a module is by calling angular.module(...). ngMocks loads "itself" by calling:
angular.module('ngMock', ['ng']).provider(...).config(...);
You don't need to declare a module as a dependency to load it. You can just include angular.module('<moduleName>', [<moduleDependencies>...]); in its script.
If you mean "how is ngMock automagically added to the dependency list of any module loaded using window.module or angular.mock.module, it is because ngMocks creates a custom injector, such that it takes the list of dependencies and prepends 'ngMock':
window.inject = angular.mock.inject = function() {
...
return isSpecRunning() ? workFn() : workFn;
...
function workFn() {
var modules = currentSpec.$modules || [];
modules.unshift('ngMock'); // <-- this line does the trick
modules.unshift('ng');
...
You could create your own function that prepends your module in the list of dependencies before instantiating, but I hardly believe this will help in testing. On the contrary, it will be one more source of errors (and will result in possibly "hiding" dependency errors).

Setting initial $rootScope defaults don't seem to work

I would like to have few global variables that are UI related (i.e. open menu state). I decided to put these in $rootScope so they're always accessible.
This is the code I've written:
(function (angular) {
angular
.module("App", [])
.run(["$rootScope", function ($rootScope) {
angular.extend($rootScope, {
ui: {
menu: false,
...
}
});
}]);
})(angular);
I've deliberately used angular.extend, to make sure that consecutive manipulations to the same object are retained. And I think it's also more clean and safe than adding several properties to any object one by one.
Problem
Upper code doesn't do anything though. When I run my application and check root scope by calling:
$("body").scope().$root.ui
I get undefined until some property within ui gets manipulated by ng-click directives on my application. Only then my ui gets a reference... But it's still not the one I've defined in the run() function but rather angular generated object property that ng-click directive generated as per expression.
What am I doing wrong?
Resolved - module got overwritten
Ia managed to resolve it myself. Code contained in the upper question isn't sufficient to show the actual problem in my application. The problem was the way I was loading module requirements and file ordering.
I'm loading files in this order:
app.js
routing.js
service.something.js
...
filter.something.js
...
So I thought to add module requirements to my app module in subsequent files (make ti actually modularized). This would make it simple to either include or exclude particular files without any runtime errors. It would also allow loading additional files dynamically as application runs.
The problem with my code was that I've overridden my original module in subsequent files. When I added all module requirements into app.js everything everything started working.
Possible workaround
I can see that I'm not the only person that would like this kind of functionality. Lasy module requirements loading is possible as per this Google groups' post.
What it does is it creates a new injector function
instanceInjector.loadNewModules = function (mods) {
forEach(loadModules(mods), function(fn) { instanceInjector.invoke(fn || noop); });
};
that can later be used by individual modules to add themselves as requirement to the main application module by doing this:
$injector.loadNewModules(["Module1", "Module2", ...]);
Although it would be much better (my opinion) if there was an additional function on Module type called requires() so one could do this instead:
angular.module("MainModule").requires(["AdditionalModule", "OtherModule", ...]);
I think that would make it more concise and easy to use and understand.

Resources