I want to import angular, instantiate the AngularJS module, and then import another file that requires that the Angular be already instantiated:
import angular from 'angular';
var app = angular.module('app', []);
import 'src/app.js';
angular.element(window).ready(function(){
angular.bootstrap(document, ['app']);
});
But Babel compiles it into this (TLDR: hoist all imports to the top)
System.register([], function (_export2) {
return {
setters: [],
execute: function () {
System.register(['angular', 'src/app.js'], function (_export) {
var angular, app;
return {
setters: [function (_angular) {
angular = _angular.default;
}, function (_srcAppJs) {}],
execute: function () {
app = angular.module('app', []);
angular.element(window).ready(function () {
angular.bootstrap(document, ['app']);
});
}
};
});
}
};
});
UPDATE: #just-boris
I was well aware of System.import().then. The problem is that app.js also imports files which make Angular components, which require that the module be instantiated.
Example imported file:
angular.module('app').controller( [ function () {} ] );
System.import().then does not wait until the dependency tree
is resolved, because it has no sense of one.
System.import('app').then(function(){
// But wait, app.js's dependencies aren't resolved!
// The Angular components aren't loaded yet!
// The following will throw errors:
angular.element(window).ready(function(){
angular.bootstrap(document, ['app']);
});
});
By design, all import statements should be available for static analysis so they must be on the top-level. See this answer for a relevant question.
If you want to load module in runtime, you should not use import for it. But you can do it with System.import instead
System.import('src/app.js').then(function() {
// deal with app.js
});
Related
I have the following provider:
(function (angular) {
angular.module('app')
.provider('$_Config', ConfigProvider);
function ConfigProvider() {
.... //routes definition
}
ConfigProvider.prototype.$get = function () {
return this;
};
ConfigProvider.prototype.getRoutes = function() {...}
//other prototype functions
})(angular);
In app.js I am using it like this:
app.config(function ($routeProvider, $_ConfigProvider) {
var routes = $_ConfigProvider.getRoutes();
routes.forEach(function(route) {
$routeProvider
.when(route.route, {
.....
})
}
Every thing work fine till it gets to testing. Here is my test:
describe('Provider: $_ConfigProvider', function () {
// load the providers module
beforeEach(module('app'));
// instantiate provider
var $_ConfigProvider;
beforeEach(inject(function (_$_Config_) {
$_ConfigProvider = _$_Config_;
}));
it('Should verify getRoutes function', function () {
var routes = $_ConfigProvider.getRoutes();
expect(Object.prototype.toString.call(routes) === '[object Array]').toBe(true);
});
});
When running the test I am getting the following error:
Error: [$injector:modulerr] Failed to instantiate module app due to:
Error: [$injector:unpr] Unknown provider: $_ConfigProvider
Note: The $_ConfigProvider is injected correctly during run-time.
You are likely not including the file where the provider is defined in in your karma.conf.js dependencies list. See this question:
Include dependencies in Karma test file for Angular app?
I would rename the $_Config to something else, '$' is usually reserved for angular-specific components.
I have a variable that contains my angular app
(was instantiated with:)
var app = angular.module('app', [...]);
And I want to get the $timeout service.
How can I get this service from the it?
I want something like:
var timeout = app.getService('$timeout');
or
app.something('$imeout', function($timeout) {
...
} // like controller() does
Where I want to use it:
define([], function () { // I can import my angular module 'app', or 'angular'
return {
'some_function': function () {
$timeout(function() { ... do something ... }, 1000);
}
}
}
This is a service (with requirejs), and my controllers will require it.
What you should do is:
app.controller("myCtrl",["$timeout", "otherService" ,function($timeout, otherService){
$timeout(function() {
otherService.updateService('Hi');
}, 3000);
}]);
I have two AngularJS services:
service1.js
'use strict';
angular.module('myModule', [])
.factory('myService1', function() {
return {
myFunction: function(options) {
if (options) {
// do stuff
}
}
};
});
service2.js
'use strict';
angular.module('myModule', [])
.factory('myService2', function() {
return {
myFunction: function(options) {
if (options) {
// do stuff
}
}
};
});
I learned the hard way from the official docs that this approach will basically remove myService1 because the module gets overwritten. My question is, do I have any options here? I would really like to be able to have my services defined in separate files. Yet, I only want one module.
Thank you for any insights.
You have to define the module just once:
angular.module('myModule', []);
And then use it as many times as you need it without setting the dependencies:
angular.module('myModule');
So either you define the module in a separate file, or if you define it in the first service, the second should look like this:
angular.module('myModule')
.factory('myService2', function() { ... });
I am getting an error when trying to attach my config class to my angular app. I get a message saying: $injector:nomod] Module 'ngLocale' is not available! I have a reference to angular.js and angular-route.js
Here is my Config Code.
module TSApplication {
export class Config {
static $inject = ["$routeProvider"];
constructor($routeProvider: ng.route.IRouteProvider) {
this.registerRoutes($routeProvider);
}
private registerRoutes(rProvider: ng.route.IRouteProvider) {
rProvider.when("/", { templateUrl: "/partials/example.html", controller: "ExampleCtrl" });
}
}
}
(function () {
var app = TSApplication.App.angularModule;
app.config(TSApplication.Config);
})();
And here is my App Module code:
module TSApplication {
"use strict";
export class App {
static angularModule = angular.module("App", ['ngRoute']);
}
}
(function () {
// Toaster Junk
})();
Am I missing something simple? If I don't include the config I do not receive an error.
It looks like you are passing TSApplication.Config to the angular config function which is treating it as a function. Therefore, in your "constructor" this isn't actually what you think it is because no instance of TSApplication.Config was created. You could remedy this by changing registerRoutes to a static method and then calling it in your constructor like this Config.registerRoutes($routeProvider);.
I am using this strategy to lazy-load stuff with RequireJS in my AngularJS app:
define([
'src/services/dependency_resolver', // resolves promise when dependencies are `require`d
'json!modules.json'
], function (dependencyResolver, modules) {
var app = angular.module('myApp', [ 'ngRoute' ]);
app.config(function ($controllerProvider, $routeProvider) {
app.lazy = {
controller: $controllerProvider.register
// <...> other providers
};
angular.forEach(modules, function (moduleConfig) {
angular.forEach(moduleConfig.routes, function (route) {
$routeProvider.when(route.path, {
templateUrl: route.templateUrl,
controller: route.controller,
resolve: dependencyResolver(moduleConfig.dependencies)
});
});
});
});
return app;
});
But I'm not sure what is the correct way test a lazy-loaded controller. It is registered like this:
define(['src/app'], function (app) {
app.lazy.controller('MainCtrl', function () {
//
});
});
And this is my current spec:
describe('`MainCtrl` controller', function () {
var Ctrl,
$scope;
beforeEach(angular.mock.module('myApp'));
beforeEach(function (done) {
require(['module/main'], done);
});
beforeEach(function () {
angular.mock.inject(function ($rootScope, $controller) {
$scope = $rootScope.$new();
Ctrl = $controller('MainCtrl', {
$scope: $scope
});
});
});
it('should ...', function () {
console.log(Ctrl);
});
});
With this spec, an error occurs when controller is being registered, because app.lazy is undefined.
So the question is how to test such controllers?
Cheers!
I was experiencing a similar problem when writing my unit test using the "lazy" property to register my controller. The problem with this approach is that when in the context of a unit test, the module config block will not be executed and as a result, app.lazy will resolve to undefined.
To solve your problem, instead of using provider registration methods to set your properties of app.lazy, the provider registration method should be used to override their counterparts on the module. In other words, your config block should now become:
`app.config(function ($controllerProvider, $routeProvider) {
app.controller = $controllerProvider.register
// <...> other providers
.......
}`
Instead of register your controller using (app.lazy):
`define(['src/app'], function (app) {
app.lazy.controller('MainCtrl', function () {
//
});
});`
you can just define like this:
`define(['src/app'], function (app) {
app.controller('MainCtrl', function () {
//
});
});`
And this should work! Hopefully this can help, and please let me know if this works out or not.
First of all, thank you for the reference you provided - the article is really interesting.
Author of the article is using AngularJs providers to implement his strategy. The thing is, that AngularJs doesn't have providers for 'specs'. So my opinion is that you should omit this strategy in your unit tests.
On this basis, I think, that you should add AMD to your spec file. Define your controller as a dependency in your spec. After this, you may just require all your specs somewhere in main-spec.js and launch your testing framework.