May be it's trivial question, but for AngularJS newbie it's a matter ^_^
What I'm trying to originally achieve is to make a dynamically inserted tag (by jQuery) with ng-click directive to work. I've searched and found that I've to get AngularJS Injector, then compile that code. So here it is the simplest form of the injector code which is NOT working for me, what's wrong with it?
Note #1: The dynamically inserted tag with ngDirective is done outside AngularJS scope.
angular.module('simpleExample', [])
.run(
[ '$rootScope',
function ($rootScope) {
$rootScope.test = "Test";
}]);
console.log(angular.injector(['simpleExample']));
// console.log(angular.injector(['simpleExample']).$compile('Text'));
http://jsfiddle.net/Zx8hr/6/
The ng module
angular.bootstrap automatically adds the ng module to the dependencies when used (manually or with ngApp)
$rootScope / $compile services are part of the ng module.
You need to use injector.invoke if you want these services.
You should probably use angular in more traditional ways.
Try this:
angular.module('simpleExample', ['ng']);
angular.injector(['simpleExample'])
.invoke(['$rootScope','$compile',
function($rootScope, $compile){
var elm = $compile('Text')($rootScope);
$rootScope.someFunctionOnRootScope = function(){
alert("Hello there!");
}
angular.element(document.body).append(elm);
}]);
Related
I'm reading http://www.alexrothenberg.com/2013/02/11/the-magic-behind-angularjs-dependency-injection.html and
it turned out that angularjs dependency injection has problems if you minify your javascript
so I'm wondering if instead of
var MyController = function($scope, $http) {
$http.get('https://api.github.com/repos/angular/angular.js/commits')
.then(function(response) {
$scope.commits = response.data
})
}
you should use
var MyController = ['$scope', '$http', function($scope, $http) {
$http.get('https://api.github.com/repos/angular/angular.js/commits')
.then(function(response) {
$scope.commits = response.data
})
}]
all in all I thought the second snippet was for the old version of angularjs but ....
Should I always use the inject way (the second one) ?
Yes, always! So this way even if your minifer converts $scope to variable a and $http to variable b, their identity is still preserved in the strings.
See this page of AngularJS docs, scroll down to A Note on Minification.
UPDATE
Alternatively, you can use ng-annotate npm package in your build process to avoid this verbosity.
It is safer to use the second variant but it is also possible to use the first variant safely with ngmin.
UPDATE:
Now ng-annotate becomes a new default tool to solve this issue.
Yes, you need to use explicit dependency injection (second variant). But since Angular 1.3.1 you can turn off implicit dependency injection, it's really helpful to solve potential problems with renaming at once (before minification).
Turning off implicit DI, using strictDi config property:
angular.bootstrap(document, ['myApp'], {
strictDi: true
});
Turning off implicit DI, using ng-strict-di directive:
<html ng-app="myApp" ng-strict-di>
Just to point out that if you use
Yeoman
there is no need to do like
var MyController = ['$scope', '$http', function($scope, $http) {
$http.get('https://api.github.com/repos/angular/angular.js/commits')
.then(function(response) {
$scope.commits = response.data
})
}]
because grunt during minify take into account how to manage DI.
Like OZ_ said, Use ngmin to minify all angular js file, like directive.js service.js. After that you can use Closure compiler to optimize it.
ref:
How to minify angularjs scripts
Build with YO
You might want to use $inject as it mentioned here:
MyController.$inject = ['$scope', '$http'];
function MyController($scope, $http) {
$http.get('https://api.github.com/repos/angular/angular.js/commits')
.then(function(response) {
$scope.commits = response.data
})
}
Use Strict Dependency Injection to Diagnose Problems
With Implicit Annotation, code will break when minified.
From the Docs:
Implicit Annotation
Careful: If you plan to minify your code, your service names will get renamed and break your app.
You can add an ng-strict-di directive on the same element as ng-app to opt into strict DI mode.
<body ng-app="myApp" ng-strict-di>
Strict mode throws an error whenever a service tries to use implicit annotations.
This can be useful to determining finding problems.
For more information, see
AngularJS Developer Guide - Using Strict Dependency Injection
AngularJS ng-app Directive API Reference
AngularJS Error Reference - Error: $injector:unpr Unknown Provider
I minified and merged all js files in one and included in html nothing is working in site.
There are so many files in js and I dont want include all one by one, so modified and merged all in one.
Is there any other way to decrease number of http calls for js files.
When minifying your AngularJS documents it is important that you follow the docs for dependancy injection, otherwise your code can break. You should make sure you are using the preferred array method an example can be seen below:
someModule.controller('MyController', ['$scope', 'greeter', function($scope, greeter) {
// ...
}]);
As seen in the official Angular JS docs: https://docs.angularjs.org/guide/di.
It seems, that's a reason of implicit dependency injection. According to the Angular JS documentation:
Careful: If you plan to minify your code, your service names will get renamed and break your app.
Use strict dependency injection instead. For example:
angular
.module("MyModule")
.controller("MyCtrl", ["$scope", "$timeout", function ($scope, $timeout) {
...
}]);
More over, consider using ng-annotate that's much easier:
angular
.module("MyModule")
.controller("MyCtrl", function ($scope, $timeout) {
"ngInject";
...
});
To follow up on #dayle-salmon 's answer, if you have your controllers like this
app.controller('DemoCtrl', function(dependency1, dependency2){
// controller code
});
Change it to
app.controller('DemoCtrl', ['dependency1', 'dependency2', function(dependency1, dependency2){
// controller code
}]);
Reason JS minificators usually change the name of the dependency that is injected. And Angular wont have a clue on what the dependency is. So, you manually declare them so it won't cause a problem after minification!
I've been trying to set up basic AngularJS functionality for a project but have been hitting a brick wall when it comes to including angular-route. Both are version 1.4.8. I'm currently using gulp-require to concatenate my JS, here's my main javascript file
// =require ../components/jquery/dist/jquery.min.js
// =require ../components/angular/angular.js
// =require ../components/angular-route/angular-route.js
$(document).ready(function() {
// =require app/app.js
}); // Doc ready is done!
And my app.js file
var app = angular.module('myApp', ['ngRoute']);
app.controller("ctrl", ["$scope", 'ngRoute', function($scope) {
$scope.test = "It works!";
}]);
I've checked and all the files are concatenating properly. The ng-app and ng-controller attributes are on my HTML file. I've tried adding and removing the ngRoute injection and switching the order of the files but to no avail. It's frustrating since I used Angular 1.4.5 in almost the exact same way without these issues popping up but I can't replicate the same here even when going back. But the {{test}} variable in my HTML is still not rendering, and basic operations like {{2 + 3}} aren't either.
EDIT: here is the link to the original error message I'm currently receiving: http://tinyurl.com/zx3k85f
EDIT 2: The parts of my HTML code that's calling the app and the controller:
<html lang="en" ng-app="myApp">
<body ng-controller="ctrl">
</body>
</html>
I'm using nunjucks for HTML dynamic generation, although I've changed the syntax for this so it doesn't conflict with Angular's double curly braces.
You can't inject module as dependency inside controller, you should remove 'ngRoute' from the controller DI inline array.
app.controller("ctrl", ["$scope", , function($scope) {
Update
Basically the real problem is you are loading your angular component script using requirejs(lazily), so while you are having ng-app="myApp" with module name start looking for myApp module, and the module has not loaded therefore it throws an error .
So I'd recommend you to don't use ng-app directive to start angular on page load. Instead you should wait until all the scripts related to angular loaded, & then to bootstrap angular app lazily using angular.bootstrap method.
Code
$(document).ready(function() {
requirejs(["app/app.js"], function(util) {
angular.bootstrap(document, ['myApp']);
});
});
ngRoute is a provider that needs to be configured in the module config section before being used. Using it within a controller does not make any sense. Here the version that will work:
angular.module('myApp', ['ngRoute']);
angular.module('myApp').controller("ctrl", ["$scope",function($scope) {
$scope.test = "It works!";
}]);
Moreover, you need to call your module using directive ng-app=myapp in the html element where you plan to render your app.
I am trying to dependency inject a module into another—the former is simply an empty module.
angular.module('module1', []);
angular.module('module2', [])
.controller('Module2Ctrl', ['module1', '$scope', function (module1, $scope) {
$scope.expression = 'hello!';
}]);
HTML:
<html ng-app="module2">
<body ng-controller="Module2Ctrl">
<h1>{{expression}}</h1>
</body>
</html>
I'm getting the dreaded Unknown provider: module1Provider <- module1 <- Module2Ctrl message.
What's going on? I believe everything is defined as it should be—though module1 has no definitions, I can't find information anywhere on what would stop this from working.
Plnkr: http://plnkr.co/edit/goMVFRNuPgG6iIpGYI1Y?p=preview
Thanks :-)
You inject providers (such as factories, services, ...), not modules. Remove the module1 injection and it will work. What you're thinking of doing is probably declaring module2 as a module dependency of module1:
angular.module('module1', ['module2']);
and then ng-app="module".
angular.module can not injected inside a controller,Only one angular.module can be injected inside another module.
angular.module('module2', ['module1'])
You should never do that angular. Only angular components are inject-able like service,controller, factory, filter, provider,etc.
For initializing angular on page you could do angular.bootstrap
angular.bootstrap(document,["module2"])
I keep receiving this error as I'm trying to implement bootstrap Modal window. What could be the cause of it? I've copy/pasted everything from http://angular-ui.github.io/bootstrap/#/modal here.
This kind of error occurs when you write in a dependency for a controller, service, etc, and you haven't created or included that dependency.
In this case, $modal isn't a known service. It sounds like you didn't pass in ui-bootstrap as a dependency when bootstrapping angular. angular.module('myModule', ['ui.bootstrap']); Also, be sure you are using the latest version of ui-bootstrap (0.6.0), just to be safe.
The error is thrown in version 0.5.0, but updating to 0.6.0 does make the $modal service available. So, update to version 0.6.0 and be sure to require ui.boostrap when registering your module.
Replying to your comment: This is how you inject a module dependency.
<!-- tell Angular what module we are bootstrapping -->
<html ng-app="myApp" ng-controller="myCtrl">
js:
// create the module, pass in modules it depends on
var app = angular.module('myApp', ['ui.bootstrap']);
// $modal service is now available via the ui.bootstrap module we passed in to our module
app.controller('myCtrl', function($scope, $uibModal) {
});
Update:
The $modal service has been renamed to $uibModal.
Example using $uibModal
// create the module, pass in modules it depends on
var app = angular.module('myApp', ['ui.bootstrap']);
// $modal service is now available via the ui.bootstrap module we passed in to our module
app.controller('myCtrl', function($scope, $uibModal) {
//code here
});
5 years later (this would not have been the problem at the time):
The namespacing has changed - you may stumble across this message after upgrading to a newer version of bootstrap-ui; you need to refer to $uibModal & $uibModalInstance.
Just an extra side note for an issue I also experienced today:
I had a similar error "Unknown provider: $aProvider" when I turned on minification/uglify of my source code.
As mentioned in the Angular docs tutorial (paragraph: "A Note on Minification") you have to use the array syntax to make sure references are kept correctly for dependency injection:
var PhoneListCtrl = ['$scope', '$http', function($scope, $http) { /* constructor body */ }];
For the Angular UI Bootstrap example you mention you should this replace this:
var ModalInstanceCtrl = function ($scope, $modalInstance, items) {
/* ...example code.. */
}
with this array notation:
var ModalInstanceCtrl = ['$scope', '$modalInstance', 'items', function ($scope, $modalInstance, items) {
/* copy rest of example code here */
}];
With that change my minified Angular UI modal window code was functional again.
The obvious answer for the provider error is the missing dependency when declaring a module as in the case of adding ui-bootstrap. The one thing many of us do not account for is the breaking changes when upgrading to a new release. Yes, the following should work and not raise the provider error:
var app = angular.module('app', ['ui.router', 'ngRoute', 'ui.bootstrap']);
app.factory("$svcMessage", ['$modal', svcMessage]);
Except when we are using a new version of ui-boostrap. The modal provider now is defined as:
.provider('$uibModal', function() {
var $modalProvider = {
options: {
animation: true,
backdrop: true, //can also be false or 'static'
keyboard: true
},
The advise here is once we have make sure that the dependencies are included and we still get this error, we should check what version of the JS library we are using. We could also do a quick search and see if that provider exists in the file.
In this case, the modal provider should now be as follows:
app.factory("$svcMessage", ['$uibModal', svcMessage]);
One more note. Make sure that your ui-bootstrap version supports your current angularjs version. If not, you may get other errors like templateProvider.
For information check this link:
http://www.ozkary.com/2016/01/angularjs-unknown-provider-modalprovider.html
hope it helps.
after checking that I had all dependancies included, I fixed the issue by renaming $modal to $uibmodal and $modalInstance to $uibModalInstance
var ModalInstanceCtrl = ['$scope', '$modalInstance', function ($scope, $modalInstance, items) {
/* copy rest of example code here */
}];