Why place $scope in the dependencies array on a controller? - angularjs

I've seen a lot of people, including the Angular docs, declare controllers like so:
app.controller('ExampleController', [$scope, $http, function($scope, $http) {
$scope.name = "Bob";
}]);
Why do we need to put $scope in the dependency array? Is this the syntax of an older version of Angular? Can we instead write it like:
app.controller('ExampleController', [$http, function($scope, $http) {
$scope.name = "Bob";
}]);
Is there a difference between the two? Thank you.

What you've been looking at is actually something like this:
app.controller('ExampleController', ["$scope", "$http", function($scope, $http) {
$scope.name = "Bob";
}]);
The reason this is done is to deal with minification. When minifying the $scope, $http would be crushed into variables like a and b since dependency injection doesn't work through minification. Angulars solution to this is to make the controller an array where you can pass in strings.
See: https://docs.angularjs.org/tutorial/step_05#-prefix-naming-convention

Related

Which one is correct way for initializing module,controller in angularJS?

Which one is correct way for initializing module,controller in angularJS
var myapp=angular.module('myApp', []);
myapp.controller('Ctrl1', Ctrl1);
myapp.controller('Ctrl2', Ctrl2);
Ctrl1.$inject = ['$scope', '$http'];
Ctrl2.$inject = ['$scope', '$http'];
function Ctrl1($scope, $http) {
}
function Ctrl2($scope, $http) {
}
or this way
var myapp=angular.module('myApp', []);
myapp.controller('Ctrl1', Ctrl1);
Ctrl1.$inject = ['$scope', '$http'];
function Ctrl1($scope, $http) {
}
myapp.controller('Ctrl2', Ctrl2);
Ctrl2.$inject = ['$scope', '$http'];
function Ctrl2($scope, $http) {
}
or doing this way
var myapp=angular.module('myApp', []);
myapp.controller('Ctrl1', ['$scope', '$http', function ($scope, $http) {} ]);
myapp.controller('Ctrl2', ['$scope', '$http', function ($scope, $http) {} ]);
I am confusing which way is correct and can you give give me the cirrect project structure of AngularJS frmawork
Any sample project for that in github always welcome
Some peoples says John Papa style which one correct way i mean most efficient way
The simpliest way is to write:
myapp.controller('Ctrl1', function($scope, $http) {
});
And you should use ngmin to parse your code before minification. It will automatically wrap the controller callback in ['$scope', '$http', function($scope, $http) {}] to avoid minification problem.
If you use gulp, use gulp-ngmin.
The second way should be the ideal way as because
It is easy to read.
Easy to maintain
Protected from minification by the injector.
Anyways all of them are correct.
But second way should be the best.
Also make sure that you wrap the code in the way to protect from variable name clashes:
(function(){
'use strict'; //another best practice
//then your code
})()
Angular's $inject method, we can explicitly declare our dependencies. This one may give problem for every controller injection. Other than you can use.
https://docs.angularjs.org/api/auto/service/$injector

Can't inject $q in Angular?

everyone.
I have a really strange (for me) problem here. I am trying to inject the $q lib in one of my controllers and when I try to console.log() it, it returns "undefined". I am injecting the same library in one of my services, and it's working there! Let me show you:
The service:
(function() { 'use strict';
angular
.module('app.grid')
.factory('GridData', GridData);
GridData.$inject = ['$http', '$q'];
function GridData($http, $q) {
...
The controller (not working):
(function() {
'use strict';
angular
.module('app.grid')
.controller('GridCtrl', GridCtrl);
GridCtrl.$inject = ['$log', '$scope', 'GridData', '$q'];
function GridCtrl($log, $scope, GridData, $rootScope, $q) {
console.log($q); // Returns "undefined"
...
I wonder if any of you guys had had this same problem before? It's probably something real stupid, like it always is, but I can't see it for some reason :(
Cheers,
H
You need to add the $rootScope to your $inject array:
GridCtrl.$inject = ['$log', '$scope', 'GridData', '$rootScope', '$q'];
Or remove it from the argument list if it's not needed:
function GridCtrl($log, $scope, GridData, $q) {
You have one too many arguments:
GridCtrl.$inject = ['$log', '$scope', 'GridData', '$q'];
function GridCtrl($log, $scope, GridData, $rootScope, $q) {
// ^
}
You're not injecting $rootScope. The $q service will be available inside your controller, it will just be referred to by $rootScope instead of $q. Remove that and it should work! Alternatively, add '$rootScope to the dependency array.

angular controller inline annotation syntax

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) {

Angular how to include $http when minifying JS

Since I'm minifying and uglifying my JS, I can't simply do the following:
var app = angular.module('app', []);
app.controller('MyController', function($scope, $http) {
// ...
});
It will throw an inject-related error since minifying it jumbles up the $scope var.
Instead, I have to do this:
app.controller('MyController', ['$scope', function($scope) {
$scope.angularIs = "awesome";
}]);
Question: Using the second approach, how do I add the http service? Something like this?
app.controller('MyController', ['$scope&$http', function($scope, $http) {
// ...
}]);
And can my angular.module('app', []); declaration stay the same, or do I have to add some type of http dependency to the []'s? Thanks!
You can just use:
app.controller('MyController', ['$scope', '$http', function($scope, $http) {
// ...
}]);
It will match then against the arguments inside function(). Your app's dependencies will always be strings, so those will be fine when minified.
use this:
app.controller('MyController', ['$scope','$http', function($scope, $http) {
// ...
}]);

Injecting $http and $scope into function within controller

I asked a similar question earlier when attempting to inject $scope and $http into a controller Cannot call method 'jsonp' of undefined in Angular.js controller. Now I'm attempting to refactor that code slightly by moving the code into a function within the controller. I'm encountering similar issues and can't seem to grasp the mechanics of dependency injection in Angular. Below is my new code. Both $scope and $http are undefined. What I'm attempting to do is make an http request when didSelectLanguage() fires and assign the resulting data to the "image" variable in the $scope from the parent controller. Can someone enlighten me as to how dependency injection is supposed to work in this example?
angular.module('myApp.controllers', []).
controller('ImagesCtrl', ['$scope', '$http', function ($scope, $http) {
$scope.didSelectLanguage=function($scope, $http) {
console.log($scope);
$http.jsonp('http://localhost:3000/image?quantity=1&language='+this.language+'&Flag=&callback=JSON_CALLBACK')
.success(function(data){
$scope.image = data;
});
}
}])
When you create your controller:
angular.module('myApp.controllers', []).
controller('ImagesCtrl', ['$scope', '$http', function ($scope, $http) {
// ...
}]);
The stuff inside the body of the controller function automatically has access to $scope and $http because of closures. Thus, there's no need to specify anything additional for a function on the $scope to have access to these things:
angular.module('myApp.controllers', []).
controller('ImagesCtrl', ['$scope', '$http', function ($scope, $http) {
$scope.didSelectLanguage = function() {
$http.jsonp('http://localhost:3000/image?quantity=1&language=' + this.language + '&Flag=&callback=JSON_CALLBACK');
.success(function(data) {
$scope.$parent.image = data;
});
}
}]);
When didSelectLanguage is run, it sees the references to $http, and reaches out of the function into the outer function to get the value of the reference; the same happens for $scope inside the success callback.
So, in short, there's no need to pass any arguments to your didSelectLanguage function, nor is there in this case any reason to use the $injector.
With the help of Michelle Tilley's comment & article I solved the problem as follows. However, I'm going to keep the question open until someone else answers or until I understand enough to write an accompanying explanation.
controller('ImagesCtrl', ['$scope', '$http', '$injector', function ($scope, $http, $injector) {
$scope.didSelectLanguage=function() {
$http.jsonp('http://localhost:3000/image?quantity=1&language='+this.language+'&Flag=&callback=JSON_CALLBACK')
.success(function(data){
$scope.$parent.image = data;
});
}
}])

Resources