I am aware of setting up a controller, service, model etc for prepping for minification. I have about 20 controllers, models and services as individual files and I want to minify and concat them all into one JS file for production.
To get an idea of how I have these files setup, here is an example:
VforumJS.controller('MainController', ['$scope', '$location', '$sce', 'MainModel', 'LogModel', 'MainDebug', 'timecode', 'Idle', function($scope, $location, $sce, MainModel, LogModel, MainDebug, timecode, Idle)
{
...
}]);
After minification, I get the error
Failed to instantiate module VforumJS due to:
Error: [$injector:unpr] http://errors.angularjs.org/1.4.1/$injector/unpr?p0=a
If I click the error link, it says Unknown provider: a
Here is where my module gets created
var VforumJsConfig = function($routeProvider, $locationProvider, localStorageServiceProvider)
{
localStorageServiceProvider.setPrefix('vforumdesktop');
$locationProvider.html5Mode(true);
$routeProvider
.when('/', {
...
})
.otherwise({
...
});
};
var VforumJS = angular.module('VforumJS', ['ngRoute','LocalStorageModule', 'ngTouch', 'ui-rangeSlider','base64','ngIdle'])
.config(['$routeProvider', '$locationProvider', 'localStorageServiceProvider', VforumJsConfig])
.constant('LogTypes', {
LOGIN: 1,
IDLE_LOGOUT: 2,
MANUAL_LOGOUT: 3,
VFORUM_OPEN: 4,
VFORUM_CLOSE: 5
})
.constant('SendLogs', false)
.constant('MainDebug', true);
Am I maybe not doing the proper minification prep in the above code where the module is created?
Here is my Gruntfile.js
'use strict';
module.exports = function(grunt)
{
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
uglify: {
all_src: {
options: {
sourceMap: true,
sourceMapName: 'source.map'
},
src: 'resources/js/**/*.js',
dest: 'composite.all.min.js'
}
}
});
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.registerTask('default', ['uglify']);
};
Your .config is definitely one of the issues. Double check and make sure that everywhere in your code that you are injecting a service/provider that you are using the in-line minification.
This is what a config injecting one provider (just $logProvider for this example) will look like after minification:
.config(function(a){
console.log("Never gets here, but a is", a);
})
When really it should look like this:
.config(['$logProvider', function(a){
console.log("a is", a);
}])
Here is a codepen: http://codepen.io/troylelandshields/pen/xGjKGV
Your VforumJsConfig line is the issue
var VforumJsConfig = function($routeProvider, $locationProvider, localStorageServiceProvider)
The function parameters get minified, and angular doesn't know where to inject them from. You need to supply them as strings ( just like your other functions ), as strings won't be altered during minification.
From the docs:
https://docs.angularjs.org/tutorial/step_05#a-note-on-minification
So you will need to add after the definition of VforumJsConfig:
VforumJsConfig.$inject = ['$routeProvider', '$locationProvider', 'localStorageServiceProvider']
Use the array syntax for VforumJsConfig so that the dependencies are defined explicitly rather than implied by the parameter names which will be minified. Instead of:
var VforumJsConfig = function($routeProvider, $locationProvider,
localStorageServiceProvider)
{
localStorageServiceProvider.setPrefix('vforumdesktop');
$locationProvider.html5Mode(true);
$routeProvider
.when('/', {
...
})
.otherwise({
...
});
};
Try:
var VforumJsConfig = ['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider, localStorageServiceProvider)
{
localStorageServiceProvider.setPrefix('vforumdesktop');
$locationProvider.html5Mode(true);
$routeProvider
.when('/', {
...
})
.otherwise({
...
});
}];
Related
I am new to Karma and would really appreciate any help understanding the reason for the error below:
Uncaught Error: [$injector:nomod] Module 'myApp.controllers' 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.
app.js
angular.module('myApp', [
'ngRoute',
'myApp.controllers',
'myApp.filters',
'myApp.services',
'myApp.directives'
]).
config(function ($routeProvider, $locationProvider) {
controllers.js
angular.module('myApp.controllers', []);
StoreCtrl.js
angular.module('myApp.controllers').
controller('StoreCtrl', ['$scope', '$http', function ($scope, $http) {
StoreCtrl.spec.js
describe('StoreCtrl', function() {
beforeEach(module('myApp.controllers'));
var $controller;
beforeEach(inject(function(_$controller_){
// The injector unwraps the underscores (_) from around the
// parameter names when matching
$controller = _$controller_;
}));
describe('$scope.filterByPrice', function() {
it('test spec', function() {
});
});
});
karma.conf.js
files: [
'public/js/scripts/angular/angular.js',
'public/js/scripts/angular-mocks/angular-mocks.js',
'public/js/scripts/angular-route/angular-route.min.js',
'public/js/app.js',
'public/js/controllers/*.js',
'tests/**/*.spec.js'
],
File Structure
Karma wasn't picking the controllers.js file before the StoreCtrl.js
I had to change the code below:
'public/js/controllers/*.js',
to
'public/js/controllers/controllers.js',
'public/js/controllers/StoreCtrl.js',
and it works now :)
I have and angularjs app.I want to concatenate all the JS files to a single file.I'm currently trying to use Grunt.js to setup an automatic build process for concatenating JavaScript files.
However my app runs without any error before concatenation.But after concatinating the files my app throws Error: $injector:modulerr
Module Error.
Below is my code after minification
angular.module('myApp', []);
var app = angular
.module('myApp', [
'ngRoute'
]);
app.config(function ($routeProvider) {
'use strict';
$routeProvider
.when('/', {
templateUrl: 'views/main.html',
controller: 'mainCntrl'
})
.when('/about', {
templateUrl: 'views/about.html',
controller: 'aboutCntrl',
controllerAs: 'about'
})
.otherwise({
redirectTo: '/'
});
});
app.controller('mainCntrl',['$scope', function ($scope) {
'use strict';
this.awesomeThings = [
'HTML5 Boilerplate',
'AngularJS',
'Karma'
];
}]);
app.controller('aboutCntrl',['$scope', function ($scope) {
'use strict';
this.awesomeThings = [
'HTML5 Boilerplate',
'AngularJS',
'Karma'
];
}]);
Any help appreciated.Thanks :)
You need to strictly follow either Inline Array Annotation of DI or $inject Property Annotation while minifying js files.
app.config(function ($routeProvider) {
'use strict';
//code
});
should be changed to below code.
Inline Array Annotation
app.config(['$routeProvider', function ($routeProvider) {
'use strict';
//code as is
}]);
$inject Property Annotation
var config = function($routeProvider) {
'use strict';
//code as is
}
config.$inject = ['$routeProvider'];
app.config(config);
Seems like the config line is your problem, try app.config(['$routeProvider', function ($routeProvider) { ... }]);
Yes, your annotation is not right. It should be
app.config(['$routeProvider', function ($routeProvider) {
'use strict';
//code
}]);
Use ng-annotate as a safe, clean and simple solution.
What it does is that when you grunt it'll annotate your definitions the proper way, so you don't have to deal with Angular's quirky way.
Run ng-annotate on
app.config(function($routeProvider) {
'use strict';
//code
});
and it'll auto-complete it for minification:
app.config(["routeProvider", function($routeProvider) {
'use strict';
//code
}]);
You can also add another step to your build workflow - grunt-ng-annotate in that case you will be able to skip almost all strict DI annotations. With this plugin you can simplify services/controllers definitions e.g.:
app.controller('mainCntrl', function ($scope) {
'use strict';
this.awesomeThings = [
'HTML5 Boilerplate',
'AngularJS',
'Karma'
];
});
It is extremely helpful when you heave a long list of services to inject into controller or another service. You don't have to remember to put each dependency twice.
this is part of my configuration file karma.conf.js:
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: '../',
// list of files / patterns to load in the browser
files: [
'app/bower_components/angular/angular.js',
'app/bower_components/angular-route/angular-route.js',
'app/bower_components/angular-mocks/angular-mocks.js',
'app/js/app.js',
'app/js/controllers/*.js',
'app/js/services/*.js',
'test/unit/*.js'
],
and this is my folders struct:
This is app.js file:
/**
* Created by Pietro on 30/12/15.
*/
'use strict';
var drfmApp = angular.module('drfmApp', [
'ngRoute','drfmControllers','ngCookies'
]);
drfmApp.config(['$routeProvider','$locationProvider',
function($routeProvider) {
$routeProvider.
when('/', {
templateUrl: 'views/login.html',
controller: 'LoginController'
}).
when('/login', {
templateUrl: 'views/login.html',
controller: 'LoginController',
}).
when('/register', {
templateUrl: 'views/register.html',
controller: 'RegisterController',
}).
when('/dashboardESCO', {
templateUrl: 'views/dashboard_esco.html',
controller: 'DashboardESCOControllers'
}).
when('/dashboardRetailer', {
templateUrl: 'views/dashboard_retailer.html',
controller: 'DashboardRetailerControllers'
}).
when('/dashboardAggregator', {
templateUrl: 'views/dashboard_aggregator.html',
controller: 'DashboardAggregatorControllers'
}).
otherwise({
redirectTo: '/login'
});
}]);
drfmApp.run(['$rootScope', '$location', '$cookieStore', '$http',
function($rootScope, $location, $cookieStore, $http) {
// keep user logged in after page refresh
$rootScope.globals = $cookieStore.get('globals') || {};
if ($rootScope.globals.currentUser) {
$http.defaults.headers.common['Authorization'] = 'Basic ' + $rootScope.globals.currentUser.authdata; // jshint ignore:line
}
$rootScope.$on('$locationChangeStart', function (event, next, current) {
// redirect to login page if not logged in and trying to access a restricted page
// $ รจ jQuery
var restrictedPage = $.inArray($location.path(), ['/login', '/register']) === -1;
var loggedIn = $rootScope.globals.currentUser;
if (restrictedPage && !loggedIn) {
console.log('Run Config: User not logge in or trying to access a restricted web page')
$location.path('/login');
}
});
}]);
I'm trying to run a simple unit test file like this (using Karma and Jasmine):
'use strict';
/* jasmine specs for controllers go here */
describe('Drfm controllers', function () {
beforeEach(module('drfmControllers'));
it('DUMMY TEST', function () {
expect(3).toBe(3);
});
});
where drfmApp is the name of the main module in app.js file
This is where drfmControllers is defined (in controllers.js):
/**
* Created by Pietro on 07/01/16.
*/
'use strict';
var drfmControllers = angular.module('drfmControllers', []);
drfmControllers.controller('DashboardESCOControllers', ['$scope',
function($scope) {
$scope.dashboard = "ESCO Dashboard";
}
]);
drfmControllers.controller('DashboardRetailerControllers', ['$scope',
function($scope){
$scope.dashboard="Retailer Dashboard";}
]);
drfmControllers.controller('DashboardAggregatorControllers', ['$scope',
function($scope){
$scope.dashboard="Aggregator Dashboard";}
]);
But I always have this error:
Error: [$injector:nomod] Module 'drfmControllers' 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.
http://errors.angularjs.org/1.4.8/$injector/nomod?p0=drfmControllers at /Users/Pietro/repos/drfmcockpit/app/bower_components/angular/angular.js:68
I read about the order of the *.js files in karma configuration file: but seems it is according to this rule [see "files" at the start of the question].
Thanks to everybody
UPDATE SOLUTION: changing the conf file with this:
// list of files / patterns to load in the browser
files: [
'app/bower_components/angular/angular.js',
'app/bower_components/angular-route/angular-route.js',
'app/bower_components/angular-mocks/angular-mocks.js',
'app/js/app.js',
'app/js/controllers/controllers.js',
'app/js/controllers/LoginController.js',
'app/js/controllers/RegisterController.js',
'test/unit/*.js'
],
It runs well. Seems something in files inspections. I don't know well..
You haven't set basePath in you configuration options. By default, it is equal to ''. In it's turn, empty string as a basePath value, makes it relative to the configuration file directory. It is described here:
If the basePath is a relative path, it gets resolved to the directory
where the configuration file is located
That means that either you should set basePath value to an absolute path, or you should change your files paths to relative, like:
files: [
'../app/bower_components/angular/angular.js',
'../app/bower_components/angular-route/angular-route.js',
'../app/bower_components/angular-mocks/angular-mocks.js',
'../app/js/app.js',
'../app/js/controllers/*.js',
'../app/js/services/*.js',
'unit/*.js'
],
I want to use lazy loading in my Angular project:
This is the relevant app.js code:
var app = angular.module('eva', ['ui.router',
'controllers', 'oc.lazyLoad']);
app.config(['$stateProvider', '$urlRouterProvider', '$httpProvider', '$locationProvider', '$ocLazyLoadProvider',
function($stateProvider, $urlRouterProvider, $httpProvider, $locationProvider, $ocLazyLoadProvider) {
$httpProvider.interceptors.push('AuthInterceptor');
$urlRouterProvider.otherwise("/");
$locationProvider.hashPrefix('!');
$stateProvider.state('challenge', {
url: '/challenges',
templateUrl: 'views/Challenges.html',
controller: 'ChallengeCtrl',
onEnter: ['$state', 'auth', function($state, auth) {
if (!auth.isLoggedIn()) {
$state.go('login');
}
}],
resolve: { // Any property in resolve should return a promise and is executed before the view is loaded
loadMyCtrl: ['$ocLazyLoad', function($ocLazyLoad) {
// you can lazy load files for an existing module
return $ocLazyLoad.load('js/controllers/ChallengeController.js');
}]
}
This is my controller definition code:
angular.module('eva').controller('ChallengeCtrl', ['$scope', 'auth','$translate', 'challengeFactory', 'userFactory', 'userService',
function($scope, auth, $translate, challengeFactory, userFactory, userService) {
I am not loading the challengecontroller.js file in the index.html file.
I include oclazyload just before app.js in the index.html file:
<script type="text/javascript" src="js/lib/oclazyload/dist/ocLazyLoad.js"></script>
<script type="text/javascript" src="js/app.js"></script>
I get this error now when I run the app:
Error: [ng:areq] http://errors.angularjs.org/1.4.7/ng/areq?p0=ChallengeCtrl&p1=not%20a%20function%2C%20got%20undefined
I tried many things for lazy loading, none of them worked. Now I just followed the example on Example
I really am in a pickle here, and I have no clue what to do to get the lazy loading working. I rather not work with requirejs.
angular config is just a function, any dependencies should be already $inject before you call this config. you may include it in <script> tag and add it to app = angular.module['app', ['depend1'])
so you change it and try it again.
app.config(function($stateProvider, $urlRouterProvider, $httpProvider, $locationProvider, $ocLazyLoadProvider) {
btw: open your Browser Dev-Tools, to check whether this file js/controllers/ChallengeController.js is loadead correctly
I'm trying to build a myApp.config module to store some settings for my app, I wrote a config.js file:
angular.module('myApp.config', [])
.constant('APP_NAME','My Angular App!')
.constant('APP_VERSION','0.3');
I added it to my app.js (angular-seed):
angular.module('myApp', ['myApp.filters', 'myApp.services', 'myApp.directives', 'myApp.controllers', 'myApp.config']).
I added it to the index.html file, and now I'm trying to figure out how to get it in my controllers, I tried:
angular.module('myApp.controllers', ['myApp.config'])
.controller('ListCtrl', ['$scope', 'myApp.config', function($scope, $config) {
$scope.printme = $config;
}])
but I'm getting:
Unknown provider: myApp.configProvider <- myApp.config
I'm probably doing something wrong here, any ideas ?
I don't think it is valid to use the module name in an injection like that. You can simply inject the constants by name, though:
angular.module('myApp.controllers', ['myApp.config'])
.controller('ListCtrl', ['$scope', 'APP_NAME', function($scope, appName) {
$scope.printme = appName;
}]);
I think the simplest approach is to add a constant using an object literal. This fits most application configuration use cases I think, because it supports a complex config object. The constant step also runs early, before other providers are registered.
angular.module('myApp').constant('cfg', {
url: 'https://myapi.com/v1/',
httpTimeout: 5000
})
To use it you just inject cfg:
angular.module('myApp').factory('user', function(cfg, $http){
// cfg and $http together at last
})
It should also be noted that SimplGy's solution means that the 'cfg' object is a constant, however the properties of that object are not. This means, that you cannot reassign 'cfg' like so:
cfg = { randomProperty: randomValue };
You CAN reassign the properties of the 'cfg' object like so:
cfg.url = 'BrandNewURL.com';
cfg.httpTimeout = 30;
Check out the use of constants in this example:
angular
.module('abp001App', ['ngRoute'])
.constant("myConfig", {
"url": "http://localhost",
"port": "80"
})
.config(function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/main.html',
controller: 'MainCtrl'
})
.otherwise({
redirectTo: '/'
});
})
.controller('MainCtrl', function (myConfig) {
// Do something with myConfig...
});