To inject dependencies, we do the following:
inject(["$scope", "$compile", function ($scope, $compile) {
...
}]);
This syntax is weird! Putting the function inside the array seems really counter-intuitive to me. Is there a good reason why it was chosen like this? Why not
inject(["$scope", "$compile"], function ($scope, $compile) {
My preferred syntax would be:
inject("$scope", "$compile", function ($scope, $compile) {
but I understand that there would be a few performance issues there. (Removed because it seems to be confusing the question.)
Sometimes, you'd want to assign a controller function to a variable, like with ngRoute (which was part of core Angular early on), instead of registering it with .controller:
$routeProvider
.when('/Book/:bookId', {
templateUrl: 'book.html',
controller: function($scope){
}
});
It helps to re-use the same variable for annotation as well.
$routeProvider
.when('/Book/:bookId', {
templateUrl: 'book.html',
controller: ["$scope", function($scope){
}]
});
Yes, it's a bit counter-intuitive, but not completely out of the ballpark of reason.
Not only performance:) It's because of the minify things. U can read about:
Angular Inject minify
Related
I am building a Website with AngularJS. I ran into problems with translations, got a hacky more or less working solution to it but i am thinking that it can be done a lot better.
I have a main controller which loads translations from database.
$http.get($rootScope.ApiUrl + '/?a=sprache&lang=' + $rootScope.lang).success(function (data) {
$scope.spr = data;
$rootScope.translations = data;
$rootScope.updateTranslations();
});
data is an array formatted like this:
{key: "translation",…}
Further on I have a controller for each state. I hoped it could do something like this:
app.controller('InventoryCtrl', [
'$scope',
'$http',
'$location',
'$state',
'$stateParams',
'$rootScope',
'$uibModalStack',
function ($scope, $http, $location, $state, $stateParams, $rootScope, $uibModalStack) {
$scope.title = $rootscope.translations.myTranslatedTitleForThisState
]);
Obviously this does not work as the get-request is not finished before this Code gets called and therefore $rootscope.translations variable is not set.
Instead I wrote the following. The updateTranslations() function is called from the loadTransition() function in MainController (above) after successfully finishing the get-request.
app.controller('InventoryCtrl', [
'$scope',
'$http',
'$location',
'$state',
'$stateParams',
'$rootScope',
'$uibModalStack',
function ($scope, $http, $location, $state, $stateParams, $rootScope, $uibModalStack) {
$rootScope.updateTranslations = function() {
$rootScope.setMetaTags($rootScope.translations.inventory_title, $rootScope.translations.inventory_description);
$rootScope.updateTranslations();
}
}
]);
I am pretty sure this can be done a lot better. Any ideas?
Maybe this answer is not a direct answer to your problem, but a possible new approach...
We have been using ui-router quite alot in recent Angular projects.
ui-router is ideal for defining routes within the application. More about that subject here.
A nice feature is the state resolvement. Meaning that the state will only resolve when the resolvement promise is resolved.
By example
angular.module('testApp').config(function($stateProvider) {
$stateProvider.state('', {
url: '/',
templateUrl: 'main.html',
resolve: {
labels: function(labelService) {
return labelService.loadLabels();
}
}
});
});
In the above example, the state / will resolve after the $http.get promise behind the loadService.loadLabels() is resolved. Meaning the template will be loaded, after all the resolvements are resolved.
In this case, your view will be loaded - after that all your labels are loaded and accessible by the controller (later the view).
A nice thing is that nested state definitions are perfectly possible.
Meaning, that you could have 1 root state, and many child state of the root state.
Here is my controllers.js file
(function(ctx,angular){
'use strict';
angular.module('app.controllers')
.controller('SearchMasterController',['$scope',function($scope){
//My Code
}]);
})(window, angular);
And this is my directives.js file
(function(ctx,angular){
function ControllerFunction(){
//My Controller Code
}
var directiveConfig = {
restrict:'E',
templateUrl:'path/to/acco.html',
controller: ControllerFunction
}
angular.module('app.directives')
.directive('acco', function(){
return directiveConfig;
});
})(window, angular);
Now my question is, can I use this acco directive with some different controller. Ideally, is there any way to get it working like
<acco ng-controller="SearchMasterController"></acco> ?
I tried doing,
<acco>
<div ng-controller="SearchMasterController"></div>
</acco>
and it seems to work.
Is it possible to use
<acco ng-controller="SearchMasterController"></acco> ?
The latter alternative looks ugly to me.
nice to heard this type of access, i have tried
<acco>hi{{name1}}
<div ng-controller="SearchMasterController">{{name1}}</div>
</acco>
<acco ng-controller="SearchMasterController">{{name1}}</acco>
<script>
angular.module('myApp', [])
.controller('SearchMasterController', ['$scope', function ($scope) {
//My Code
console.log("search");
$scope.name1 = 'james';
}])
.directive('acco', function () {
return{
restrict: 'E',
templateUrl: 'acco.html',
controller: function($scope) {
//My Controller Code
console.log("cntrlr fn");
$scope.name1 = 'semaj';
}
};
});
</script>
#that time i getting output as
cntrlr fn
search
cntrlr fn
means if we are using like
<acco>hi{{name1}}
<div ng-controller="SearchMasterController">{{name1}}</div>
</acco>
then we can access both controllers but when we are using like
<acco ng-controller="SearchMasterController">{{name1}}</acco>
we can't access SearchMasterController and it's not loaded also..
Yes you can use some different controller for your directive, but there is some best practice
Use controller when you want to expose an API to other directives. Otherwise use link.
The way you tried to use controller doesn't make much sense
<!--here acco and ng-controller both are directives,
in your directive's 'ControllerFunction' and ng-controller's 'SearchMasterController'
has the same controll (scope) for 'acco' rendered html.
In that case your directive's controller overrite ng-controller functionality.
So leave 'ng-controller',
if you need any functionality in your directive
then pass those functionality using =,&,#-->
<acco ng-controller="SearchMasterController"></acco>
I see the following angularjs controller syntax structure all the time.
angular.module('7minWorkout').controller('WorkoutController',
['$scope', '$interval', '$location',
function ($scope, $interval, $location)
{
}]);
Why the repetition in the parameter names? Why not just like this
angular.module('7minWorkout').controller('WorkoutController',
['$scope', '$interval', '$location',
function ()
{
}]);
or
angular.module('7minWorkout').controller('WorkoutController',
[
function ($scope, $interval, $location)
{
}]);
The array syntax will help you with minification/uglify of your js code.
angular.module('7minWorkout').controller('WorkoutController',
function ($scope, $interval, $location) {
// code here
});
Will be minified and mangled as:
angular.module('7minWorkout').controller('WorkoutController',
function (a, b, c) {
// code here
});
So Angular won't be able to figure out which dependencies to inject
On the other hand, using the array declaration:
angular.module('7minWorkout').controller('WorkoutController',
['$scope', '$interval', '$location', function ($scope, $interval, $location) {
// code here
}]);
Will be minified as :
angular.module('7minWorkout').controller('WorkoutController',
['$scope', '$interval', '$location', function (a, b, c) {
// code here
}]);
So Angular will know what a, b and c represent.
There's also another way to inject variables if you use your first example code like below:
WorkoutController.$inject = ['$scope', '$interval', '$location'];
or
angular.module('7minWorkout').controller('WorkoutController', /* #ngInject */
function ($scope, $interval, $location) {
// code here
});
which will create the $inject method mentioned above when the code is annotated.
So, there are mainly four kinds of annotation:
Implicit Annotation - the first example code
Inline Array Annotation - the second example code
$inject Property Annotation - the $inject method
$ngInject Comment Annotation - the #ngInject method
ng-annotate
Tools like ng-annotate let you use implicit dependency annotations in your app and automatically add inline array annotations prior to minifying. If you decide to take this approach, you probably want to use ng-strict-di.
For more information, see AngularJS Developer Guide - Using Strict Dependency Injection.
This "repetion" is to make it safe for minification:
AngularJS - Controllers, Dependencies, and Minification
or you can use following syntax, according to popular angular-styleguide https://github.com/johnpapa/angular-styleguide
angular.module('7minWorkout')
.controller('WorkoutController', WorkoutController);
WorkoutController.$inject = ['$scope', '$interval', '$location'];
function WorkoutController($scope, $interval, $location) {
}
You could write the first version since it just omits the parameters of the function which are also accesible via arguments inside the function. So you would avoid the repition but slicing the arguments property is also not really efficient (compared to just type out the parameters).
As the others answers stated the repition is to make it safe for minification.
The first controller syntax makes it possible to minify/uglify the javascript code with the use of tools like ngmin. I'm not quite sure if the 2nd and 3rd options you have provided are viable options to create a controller, but in any case they will not be minified correctly since the tools will not now what the providers are. I would either suggest to use option 1 or option 3 (without the brackets) to create a controller. Note that option 3 will not be minified correctly by automated tools.
Some Useful information about creating controllers:
AngularJS Developer Guide - Controllers
option3 without brackets
angular.module('7minWorkout').controller('WorkoutController', function ($scope, $interval, $location)
{
//Your Code
});
I have this controller attached to a div:
.controller('ShowInverterConnectController', ['$scope', '$location', function($scope, $location) {
....
}])
I would like to use the $location argument of it.
I am currently doing this:
angular.element('.ng-scope').scope().$apply(function() {
console.log('test:', angular.element('.ng-scope').scope().$location);
});
But $location is coming out undefined, is there anyway to use $location?
Thanks
Not sure what you are trying to do with Angular service outside of the app, but I assume you have a good reason, because in many cases this will be considered bad practice. Anyway.
$location is not a property of the scope, so you can't get it like you are trying. However you can use $injector service to retrieve other services like $location:
angular.element('.ng-scope').scope().$apply(function() {
console.log('test:', angular.element('.ng-scope').injector().get('$location'));
});
I'm new to Angular.js which is why I have a basic question regarding routing. I figured out how to create routes and inject specific .htmls by $routeProvider
var app = angular.module('test', ['ngRoute']);
app.config(function($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'routes/view2.html'
});
});
but what I really don't get is how content or function of view2.html are handled in Angular.
Lets take view2.html. It has a <p> with some text in a specific color. Nothing to special. But also it has a little slideshow which is called by $('slideshow').cycle() function.
All what happens is it displays me the <p> tag in a different color and no slideshow function is called on my rootsite of the app.
Could you give me some approach how to actually solve this?
Thanks
Just load required view and then compile it. During compilation Angular processes all directives in view.
If you want to do this proper(Angular) way you should put such code like $('slideshow').cycle() inside of directive. And then use it like
<div my-slideshow=""></div>
angular.module('myModule', [])
.directive('mySlideshow', [function () {
return {
restrict: 'A',
link: function (scope, element) {
element.cycle();
}
}
}]);
Directives documentation
Much more comprehensive documentation