I am using the generator-angular-fullstack for my app and have come into a problem when minifying / uglyfying my code.
Before minifying my code i could use services and they would work fine but afterwards i get the following error:
[$injector:unpr] Unknown provider: aProvider <- a
I read that i need to add inline annotations to my controller like this (to stop the minify process from destroying the service:
app.controller('mainController', ['$scope', '$http', function($scope, $http) {
$scope.message = 'HOORAY!';
}]);
generator-angular-fullstack creates controllers like this:
(function () {
class EmployeesearchComponent {
constructor($scope, $rootScope, $state, $stateParams, elasticservice, $mdDialog) {
$scope.message = 'HOORAY!';
};
}
angular.module('myApp')
.component('employeesearch', {
templateUrl: 'app/employeesearch/employeesearch.html',
controller: EmployeesearchComponent
});
})();
Where am i supposed to add the services as strings?
Thanks,
I needed to add the strings above the constructor field:
static $inject = ['$scope', '$http']
Another solution is to change the controller key to have an array with the parameters' names and the controller class at the end, like so:
[...]
.component('employeesearch', {
controller: ['$scope', '$rootScope', '$state', '$stateParams', 'elasticservice', '$mdDialog', EmployeesearchComponent]
});
But you should really think about adding these annotations during your build process, it would make you code cleaner. If you're using build systems like gulp or grunt there are libraries that allow you to do this just by adding a single extra line to your build script. You can find it as "ng-annotate".
Related
I have an app which uses a lot of different js files. When I compile the app normaly with gulp everything works well, but when I compile everything in one file to minify it, I get an error (Uncaught Error: [$injector:modulerr]).
app-55bb2aca73.js:4 Uncaught Error: [$injector:modulerr] http://errors.angularjs.org/1.5.8/$injector/modulerr?p0=app&p1=Error%3A%20%…http%3A%2F%2Flocalhost%3A8080%2Fbuild%2Fjs%2Fapp-55bb2aca73.js%3A4%3A30075)
at app-55bb2aca73.js:4
...
Here is my gulpfile.js (use Laravels elexir plugin):
mix.scripts([
/*libs*/
'../../../node_modules/jquery/dist/jquery.slim.min.js',
'../../../node_modules/bootstrap/dist/js/bootstrap.min.js',
'../../../node_modules/angular/angular.min.js',
'../../../node_modules/angular-cookies/angular-cookies.min.js',
'../../../node_modules/pickadate/lib/compressed/picker.js',
'../../../node_modules/pickadate/lib/compressed/picker.date.js',
'../../../node_modules/pickadate/lib/compressed/picker.time.js',
'app.js',
'config/*.js',
'angular/controller/*.js'
], 'public/js/app.js');
Here the app.js:
var app = angular.module("app", ['ngCookies'], function ($interpolateProvider) {
$interpolateProvider.startSymbol('<%');
$interpolateProvider.endSymbol('%>');
});
For example here the begin of a controller:
app.controller('someCtrl', function ($scope, $window, $http, $cookies) {
Someone got any idea why this is not working in one file?
When you minify, the controller method names get stripped out. Need to include in this way to have a reference:
app.controller('someCtrl', ['$scope', '$window', '$http', '$cookies'
function ($scope, $window, $http, $cookies) {
// ...
}
]
More here: https://docs.angularjs.org/guide/di
This might be because the system angular uses for injecting dependencies according to the names of the variables passed as parameters. If you are minifying your files into a single one and variables are not keeping the same original name, you should inject the dependencies manually as follow:
var myApp = function ($interpolateProvider) {
$interpolateProvider.startSymbol('<%');
$interpolateProvider.endSymbol('%>');
}
myApp.$inject = ['$interpolateProvider'];
angular.module("app", ['ngCookies'], myApp);
... and in your controller:
app.controller('someCtrl', controlFn);
var controlFn = function ($scope, $window, $http, $cookies) {};
controlFn.$inject = ['$scope', '$window', '$http', '$cookies'];
To describe my hurdle, A little back story. I was injecting all the requirejs path files(directives basically) which contains any directive to my main module in the app.js, which was working perfect. Its somewhat like
define(['angularAMD', 'angular-route', 'angular-resource', 'angularTranslate', 'angularTranslateLoaderStaticFiles', 'bootstrap', 'angular-idle', 'loadingMaskDirective', 'multiselectDirective', 'treeview.directive', 'tabs', 'checklist.directive'], function(angularAMD) {
var app = angular.module("myApp", ["ngRoute", "ngResource", "ngTable", "myApp.directives", 'ui.bootstrap', 'flow']);
app.config(....){
/**some route provider**/
}...
angularAMD.bootstrap(app);
return app;
I have defined all directives and also injected them to main module. But I want to define some directive in their indivisual controller to reduce initial load. There has to be some method. Right !!
And code in my directive js files looks like..
define(['angular'], function() {
angular.module('myApp').directive('SomeDirective',
['$parse', '$compile', '$rootScope', '$filter', function($parse, $compile, $rootScope, $filter) {
.........
So, when I try to define the same in page controller not in app.js, It doesn't work. However I am amazed that the factory function in this case works but not directive.
Any help will be appreciated. Thanks
Have you tried to use app to create the directive?
define(['app'], function(app) {
app.directive('SomeDirective',
['$parse', '$compile', '$rootScope', '$filter', function($parse, $compile, $rootScope, $filter) {
.........
An alternative provided by angularAMD is:
define(['angularAMD'], function(angularAMD) {
angularAMD.directive('SomeDirective',
['$parse', '$compile', '$rootScope', '$filter', function($parse, $compile, $rootScope, $filter) {
.........
The benefit of 2nd approach is to allow loading of directive before loading of your app.js. See Loading Application Wide Module for more detail.
I have just started with AngularJS
The following code gives an error in the console.
Unknown provider: $scopeProvider <- $scope <- newActiveOrdersModel . I have researched but it looks like Unknown Provider error can happen for a variety of reasons.It would be nice if anyone could point out where I am going wrong ?
var app;
(function(angular){
app = angular.module('OrdersDashboard',[]);
app.config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/current/new', {templateUrl: 'orders/partials/new_current', controller: 'newActiveOrdersCtrl'}).
otherwise({redirectTo: '/'});
}]);
app.service('newActiveOrdersModel', ['$scope', '$rootScope',
function($scope, $rootScope){
this.Orders=["This is a test order"];
this.fetchOrders = function(){
console.log("This is a test order");
this.Orders=["This is a test order1111"];
};
}]);
app.controller('newActiveOrdersCtrl', ['$scope', '$rootScope', 'newActiveOrdersModel',
function($scope, $rootScope, newActiveOrdersModel){
$scope.test="Hello World";
}]);
})(angular);
It seems like Angular Js cannot recognize "newActiveOrdersModel".
This just a guess but I don't know why you have $scope listed as a dependency of your service. I think something like this
app.service('newActiveOrdersModel', ['$rootScope',
function($rootScope){..}]
will solve the error. Also I wouldn't include $rootScope unless you absolutely need it. It's generally considered bad practice in Angular to store stuff in the $rootScope.
I have a MyResource service defined like this:
angular.module('resourceApp')
.factory('MyResource', ['$resource', function($resource) {
return $resource('/data');
}]);
And then I have a controller which uses MyResource as a dependancy:
angular.module('resourceApp')
.controller('MainCtrl', ['MyResource', function($scope, MyResource) {
$scope.data = MyResource.get(); // <-- this is where the error occurs
}]);
When I define the dependancy like above, using an Inline Array Annotation, I get an error "MyResource is undefined" at the line marked with the comment.
But if I change the syntax to Implicit Annotation:
angular.module('resourceApp')
.controller('MainCtrl', function($scope, MyResource) {
$scope.data = MyResource.get();
});
I somehow magically get things working!
The question is: what's wrong with the first one? I could leave the implicit annotation, but the documentation says that it won't survive the minification.
You are forgetting the $scope in the first one, it should be:
anguar.module('app').controller('CTRL', ['$scope', 'MyService', function($scope, Service)
Currently you have no scope, and the $scope variable actually points to the service
You forgot to specify the $scope in your array:
.controller('MainCtrl', ['$scope', 'MyResource', function($scope, MyResource) {
I'm just about to write tests for my angularjs-app. However when Im trying to run the test which is very simpel one i get the following error.
Error: [ng:areq] Argument 'MyPageController' is not a function, got undefined
I'll provide code for the setup of my controllers, config etc.
Route
var myPageApp = angular.module('myPageApp', ['ngRoute', 'ngAnimate', 'ngSanitize', 'app.controller', 'app.service', 'app.filter', 'app.config'])
.config(['$routeProvider', function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'App_AngularJs/partials/myPage/myPage.htm',
controller: 'MyPageController',
reloadOnSearch: false,
});
}]);
Controller
var myPageApp = angular.module('app.controller', ['oci.treeview', 'ui.bootstrap'])
.controller('MyPageController', ['$scope', '$routeParams', '$location', '$timeout', '$filter', '$modal', 'myPageService',
function ($scope, $routeParams, $location, $timeout, $filter, $modal, myPageService) {
init();
function init() {
$scope.page = { value: $routeParams.page || 1 };
}
}]);
Simpel test
'use strict';
describe('Testing MyPageController', function(){
var scope;
//mock Application to allow us to inject our own dependencies
beforeEach(angular.mock.module('myPageApp'));
//mock the controller for the same reason and include $rootScope and $controller
beforeEach(angular.mock.inject(function($rootScope, $controller){
//create an empty scope
scope = $rootScope.$new();
//declare the controller and inject our empty scope
$controller('MyPageController', { $scope: scope });
}));
// tests start here
it('should map routes to controllers', function () {
module('myPageApp');
inject(function ($route) {
expect($route.routes['/'].controller).toBe('MyPageController');
expect($route.routes['/'].templateUrl).
toEqual('App_AngularJs/partials/myPage/myPage.htm');
});
});
it('should have variable assigned = "1"', function(){
expect(scope.page.value).toBe(1);
});
});
My wildest and best guess is that i need to mock app.controller but how? Everything starts out with myPageApp which holds references to service, controller etc etc..
I think your issue is that routing and the controller are trying to load different modules viz "myPageApp" and "app.controller" and in your test with beforeEach you are trying to load 'myPageApp' module to which router is associated but not the controller.
So it seems to me that either you use same module for both router and controllers. Or try loading both modules in the test. Still I believe associating the router and controller with same module makes more sense.
An small example as below. Extract the application module in common js file (may be call it app.js)
var myApp = angular.module(
'myApp');
Now define router as
myApp.config(function ($routeProvider) {
$routeProvider
.when('/testUrl', {
templateUrl: '/myApp/views/test-view',
controller: 'TestViewController'
})
Similary define controller as
myApp.controller('TestViewController',[your dependencies goes here])
And now in your tests
beforeEach(module('myApp'));
This will work for sure. Hope it helps.