I made a little fiddle here. In the example below, there are 3 controllers:
1st is a regular controller.
2nd I changed ordering of controller constructor parameters
3rd Assigned value to local $scope instead of $rootScope.
2nd controller shows that even I when changed ordering and number of parameters, value still gets assigned to root scope. From this I conclude angular somehow knows names of parameters for a function, regardless of their order? (kinda like named parameters?) This sounds weird to me. How can parameter names mean something outside of function's own 'curly brackets'?
3rd controller shows, all local scopes are a copy of $rootScope, and {{variable}} convention points to variable inside local scope, instead of the global root scope.
Am I right in these two conclusions?
index.html :
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular.js"></script>
<script src="script.js"></script>
</head>
<body ng-app="myApp" ng-controller="myController">
<div ng-controller="myController">
<h3>Echo: {{one}}</h3>
</div>
<div ng-controller="myController2">
<h3>Echo: {{two}}</h3>
<h3>Echo: {{three}}</h3>
</div>
<div ng-controller="myController3">
<h3>Echo: {{three}}</h3>
</div>
</body>
</html>
script.js
var app = angular.module('myApp',[]);
app.run(function($rootScope) {
$rootScope.today = new Date();
});
app.controller("myController", function($rootScope, $scope){
$rootScope.one = 'root scope one';
});
app.controller("myController2", function($scope, $scope, $rootScope){
$rootScope.two = 'root scope two';
});
app.controller("myController3", function($scope, $scope, $rootScope){
$scope.three = '~scope three';
});
outputs:
Echo: root scope one
Echo: root scope two
Echo:
Echo: ~scope three
Angular's dependency injection can infer the service to be injected based on the name. So yes, if you name the parameters according to the name of the services, then Angular will infer the correct service and the parameter ordering is irrelevant. This is not minification-safe, if you will be minifying your code you need to use one of the other approaches for injection. See section on Implicit Annotation in Angular's guide to Dependency Injection.
There is a single $rootScope which is injected into each of your controllers, so they are not copies of each other but are the same object. Local scopes inherit from $rootScope via prototypical inheritance. Therefore, if you attempt to access a property on a local scope, Angular will first check on the local scope for the property but if it does not exist, it will search the parent scope (then the parent scope of the parent scope etc.) See Angular's guide to Scope especially the section on Scope Hierarchies.
Related
I'm still very new at this and this is my first attempt to making an app without following any guide. For some reason my output in the webpage is {{$scope.products}} instead of the actual values. Can anyone tell my why it won't load the angular code from the controller?
index.html
<<!doctype html ng-app="MyFirstApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainController as ctrl">
{{ctrl.name}}
{{"Hello World"}}
</body>
</html>
app.js
var app = angular.module('MyFirstApp', [])
.controller('MainController', function(){
this.name = "Joe";
});
Your snippet contains some errors:
<!doctype html ng-app="MyFirstApp"> : ngApp directive is too high. Please put it in the <body> tag at least.
ng-controller="MainController as ctrl": if it is your very first AJS example, be aware that controllerAs is a best practice, but a bit advanced. This choice will condition slightly the controller code.
{{products.title}}: products is an array!
... .controller('MainController',[$scope function($scope){: the second argument of controller method is an array, so between $scope and function a comma is needed. In your case the array must be: ['$scope',function($scope){...}]. For more info pls see https://docs.angularjs.org/guide/di
$scope.products = [...]; : in order to avoid controllerAs antipattern you must use this.products.
Please update your code.
you need to put the dependancy to your controller between '' and
you are missing some thing after $scope
.controller('MainController',['$scope',function($scope){
}]);
and there are no iterate for the array in your controller to be bind in html
var app = angular.module('MyFirstApp', [])
.controller('MainController', function(){
this.name = "Joe"
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="MyFirstApp" ng-controller="MainController as ctrl">
{{ctrl.name}}
</div>
AngularJS documentation can be quite confusing.
Assigning values to the $scope is considered a bad practice. This is one of the things that the controllerAs syntax solves. So instead of adding the products to $scope.products -- add them to this.name.
Then in your view you will access them with {{ctrl.name}}
I hope this helps.
How to initialise value inside controller function with AngularJS tried multiple time but not getting proper answer??
You can inject $scope in your controller function. Then you can define any variable inside $scope.
Example
.controller('TestController', ['$scope', function($scope) {
$scope.message = 'Hello';
}])
As you can see in the above example I have injected $scope to TestController and defined message variable inside it.
Note that all the variables defined in a controller scope are accessable by the view belonging to that controller. So you can access the value of $scope.message in your DOM as
<div ng-controller="TestController">
{{message}}
</div>
On the screen you will see the text Hello
Angular Structural Question
I am new to angular.js and am just wondering how to go about performing a certain situation.
So basically, what I have got is a container:
<div ng-controller="ContainerController">
<container></container>
</div>
And the container controller and directives.
<script type="text/javascript" src="ContainerController.js"></script>
<script type="text/javascript" src="ContainerDirectives.js"></script>
Now the directives replaces the <container> tag with an example html: <example>{{ data }}</example>
Now within the scope of the ContainerController I have defined data as a string. (This is all example purposes). However when the directive accesses replaces it, it is unable to find the variable, due to scope.
The reason that this happens is because the ContainerDirective script's scope is not within the ContainerController scope. Meaning it is unable to access the variable.
Im just not sure on structure practices for these kinds of situations. Where do I put everything so the ContainerDirective can access the ContainerController scope.
I hope i have explained everything good enough
EDIT:
Test.js
(function(){
angular.module('test', []);
})();
TestController.js
(function(){
angular
.module('test')
.controller('TestController', [
'$scope',
TestController
]);
function TestController($scope) {
$scope.test = 'test';
}
})();
TestDirective.js
(function(){
angular.module('test').directive('test', function () {
return {
replace: true,
templateUrl: 'src/test/view/test.html',
link: function (scope, element, attrs) {
}
};
});
})();
test.html
<example>ClickMe</example>
index.html - body
<body ng-app="App" layout="row" ng-controller="TestController as page">
<test></test>
<script src="src/test/Test.js"></script>
<script src="src/test/TestController.js"></script>
<script src="src/test/TestDirective.js"></script>
<script type="text/javascript">
angular
.module('App', ['test']);
</script>
</body>
For reasons I have renamed certain variables and deleted a lot of data, but this is the core, and I am struggling to see anything wrong with this.
Error: [$interpolate:noconcat] Error while interpolating: abc/{{test}}
Strict Contextual Escaping disallows interpolations that concatenate multiple expressions when a trusted value is required.
So I figured out what was wrong in the end. Basically angular wont allow iframe of another location to be printed unless you first:
Give them the full url.
Then allow external url as a trusted website.
TO do this I had to basically add:
in the Test.js
angular.module('test', []).config(function($sceDelegateProvider) {
$sceDelegateProvider.resourceUrlWhitelist($sceDelegateProvider.resourceUrlWhitelist().concat([
'http://www.test.com/**'
]));
});
This basically took my whitelist and concatinated the new url to it.
Then inside test.html:
<example><iframe ng-src={{src}}></iframe></example>
I'm pretty new to Angular and I'm trying to build an app.
I use ng-include to insert my view, depending on the currentURL variable of my main controller.
When I try to access the main controller via $parent from the ng-included file, all I get is undefined.
My goal is to change the currentURL variable to update the view.
Here is my code:
index.html
<body ng-controller="mainCtrl as main">
currentURL : {{main.currentURL}}
<div ng-include="main.currentURL"></div>
<script src="/vendors/angular.min.js"></script>
<script src="/modules/login.js"></script>
<script src="app.js"></script>
</body>
app.js
angular
.module('mcaApp', ['login'])
.controller('mainCtrl', mainCtrl);
function mainCtrl() {
var vm = this,
baseURL = 'views/';
vm.currentURL = baseURL + 'login.html';
}
views/login.html
<div ng-controller="loginCtrl as login">
<h1>LOGIN</h1>
</div>
modules/login.js
angular
.module('login', [])
.controller('loginCtrl', loginCtrl);
function loginCtrl() {
var vm = this;
console.log(vm.$parent); // undefined
}
As you want to access mainCtrl which was inside loginCtrl controller then you need use $parent to access parent controller scope.
But the thing is you are loading loginCtrl controller view using ng-include so your controller is loaded in the child scope of the mainCtrl, because ng-include create a child scope from current scope.
For that reason you need use $parent.$parent to access mainCtrl scope from loginCtrl
Code
function loginCtrl($scope) {
var vm = this;
console.log($scope.$parent.$parent); // this would contain mainCtrl
}
Better approach would be to use controllerAs syntax or follow dot rule while defining objects so that prototypal inheritance gets followed.
I was not able to find in documentation if it is possible to reference a controller using a similar syntax to the one used to reference modules:
angular.module('App').controller('Ctrl');
That does not seem to work!
This is in angular 1.2
Here is link to documentation http://docs.angularjs.org/guide/controller
In paragraph with title "Adding Behavior to a Scope Object" you can see example how to use syntax like you gave above.
JS
var myApp = angular.module('myApp',[]);
myApp.controller('DoubleCtrl', ['$scope', function($scope) {
$scope.double = function(value) { return value * 2; };
}]);
HTML
<body ng-app="myApp">
<div ng-controller="DoubleCtrl">
Two times <input ng-model="num"> equals {{ double(num) }}
</div>
</body>
I don't think there are a lot of reasons to be creating controllers in services, other than for templating purposes, but of course you can!
You can use the $controller service to create instances of controllers on demand. If the controller requires a $scope, you'll have to pass it as a local: $controller("MyController", { $scope: otherScope.$new() }). AngularJS does the $scope bit for you when a controller is created internally.
See $controller for (slightly) more details.