having same nested directives:
<div mydir="a">
<div mydir="b">
</div>
</div>
if mydir requires ?^mydir it always get itself's controller.
test_plunk
is it possible to access parent's controller?
According the angular documentation on jqLite, you can call controller() to retrieve the controller for any given element:
controller(name) - retrieves the controller of the current element or its parent.
By default retrieves controller associated with the ngController directive.
If name is provided as camelCase directive name, then the controller for this
directive will be retrieved (e.g. 'ngModel').
Within your link function, you can retrieve the parent controller by calling controller() on the parent element and passing in the name of the directive:
var parentCtrl = iElement.parent().controller('mydir');
$scope.$parent.a;
shall give you a
$scope is the scope injected by angular
$parent is a keyword reference to the parent scope from any scope in angular.
Yes this is JavaScript, and as was asked in the question, AngularJS powered Javascript
Related
I'm trying to learn to build custom directives in AngularJS. Presently I am using AngularJS 1.5.8.
I am trying to create an example of a directive with an isolate scope where the controller scope is not visible, so that I can selectively expose things by adding them to 'scope: {}.' In this example, what I expect to get is 'Name: Street:' because ctrl.customer should be unavailable to the directive. Then later I would add "customer: '='" to "scope: {}" and I would get "Name:David Street:123 anywhere street". Unfortunately, I am getting "Name:David Street:123 anywhere street" from this directive as it is written.
things I have tried:
setting "bindToController: true"
removing "scope: {}" and setting "bindToController: {}" (so I add "customer: '='" to that)
setting "bindToController: false" (might as well, right?)
repeatedly hitting shift-F5 after loading the html so make sure that I just don't have the old file cached.
testScope.js:
var app = angular.module('scopeModule',[]);
app.controller('Controller',[function(){
var vm = this;
vm.customer = {
name: 'David',
street: '123 anywhere street'
};
}]);
app.directive('sharedScope', function() {
return{
scope:{},
template: 'Name:{{ctrl.customer.name}} Street:{{ctrl.customer.street}}',
controller: 'Controller',
controllerAs: 'ctrl',
bindToController: true
};
});
index2.html:
<!doctype html>
<html ng-app="scopeModule">
<body>
<shared-scope></shared-scope>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<script src="testScope.js"></script>
</body>
</html>
Controller is the controller of sharedScope directive. It is a single entity. this in directive's controller is ctrl in directive's template, because both controller and template belong to a directive.
There's no reason to isolate directive's scope from itself.
Isolated scope is isolated from the scopes of other directives. From the reference:
{...} (an object hash): A new "isolate" scope is created for the
directive's element. The 'isolate' scope differs from normal scope in
that it does not prototypically inherit from its parent scope. This is
useful when creating reusable components, which should not
accidentally read or modify data in the parent scope.
This means that if sharedScope directive has no controller and parent directive has Controller controller, this
<div ng-controller="Controller as ctrl">
<shared-scope></shared-scope>
</div>
will result in
Name: Street:
output.
I have a controller with
$scope.Id = 'something';
In html
<div ng-include="~[some path]/something.cshtml'" ng-controller="ChildController" id="#{{Id}}" ng-init="Id = Id"></div>
In generate HTML, id="#something" is correctly generated.
But in childcontroller,
$scope.Id is 'undefined'.
It looks lik ChildController is initiated before its "parent" conroller. What can I do about this?
The problem is because ng-controller & ng-include both does create a new scope which is prototypically inherited from parent.
Use dot rule while dealing with scope hierarchy/inheritance.
$scope.data = {Id :'something' }
On html you need to use it like
{{data.Id}}
Demo Here
Edit
You could not load .cshtml file form its path you should have to load it from the ASP.NET MVC controller's action because it can have C# content that needs to parse through C# view engine before rendering it on view.
I have created a test located on plunker at this address: Full example on plunker
Here is the child controller which works:
child.directive('child', function(){
return{
restrict:'E',
templateUrl: 'child.html',
link: function(){},
controller:['$scope', function($scope){
this.inherited = $scope.test;
this.local = "child";
}],
controllerAs:'child'
};
});
I am expecting the controller located in child.js to be a child controller of the controller in script.js. This would mean that if I want to access a variable added to the scope of parent controller from the child controller, I would need to access it using $scope.$parent. Can someone explain why these are the same scope?
By default, directives do not create a new scope. So in your example $scope in the directive will be the same value as the scope that the controller is contained in. The scope is not inherited - they are the same scope.
So for this markup:
<div ng-controller="SomeController">
<child></child>
</div>
scope in SomeController will be the exact same object as scope in your directive. If you did $scope.$parent in the directive, you would actually be accessing the parent scope of SomeController. This is equivalent to
scope: false //default for directives
If you add:
scope: true
to your directive definition, then the directive will create a new scope that prototypically inherits from the parent scope. In this situation,
<div ng-controller="SomeController">
<child></child>
</div>
Now $scope.$parent in the directive will be the $scope of SomeController. Also, since it prototypically inherits, the directive will have access to methods and properties defined on $scope.$parent, with the caveats and complications that come with prototypically inheritance in javascript.
If you use:
scope: {}
Now $scope.$parent in the directive will still be the $scope of SomeController, but the new scope will not prototypically inherit from the parent, so you will not have access to methods and properties defined on $scope.$parent.
The child scope inherits from the parent scope, so anything you define in the parent will appear in the child scope. Keep in mind that this is a new scope, so modifications won't affect the parent directly without using the $scope.$parent scope. Take a look at this question and the accepted answer: AngularJS access parent scope from child controller
In directives the parent scope is inherited by default:
https://github.com/angular/angular.js/wiki/Understanding-Scopes
I have an AngularJs app. I use Controllers for some child scopes. In every Controller I can set a number of variables that belong to the corresponding Child Scope. When AngularJs instantiate a controller, there is a constructor where I can set a default value to my child-scope variables.
Do I have a controller "destructor"? How do I know when a controller is closing and the scope is being cleaned (destroyed by the $destroy function)?
Thanks!
You have to listen to the $destroy event, e.g.:
function MyController($scope, ...) {
...
$scope.$on("$destroy", function handler() {
// destruction code here
});
}
Relevant docs: https://docs.angularjs.org/api/ng/type/$rootScope.Scope
To my understanding, controller is responsible for preparing the model, and pass the model to the directive which is responsible for updating DOM.
So when creating a new directive, why there is a controller inside?
Does this mean that I can do something like connecting server inside a directive?
app.directive('hover', function () {
return {
restrict: 'E',
controller: function ($scope) {
// what is the controller for?
...
}
}
}
});
From the docs on $compile service:
controller
[…] The controller is instantiated before
the pre-linking phase and it is shared with other directives (see
require attribute). This allows the directives to communicate with
each other and augment each other's behavior. The controller is
injectable (and supports bracket notation) with the following locals:
$scope - Current scope associated with the element
$element - Current element
$attrs - Current attributes object for the element
$transclude - A transclude linking function pre-bound to the correct transclusion scope. The scope can be overridden by an optional first argument.
function([scope], cloneLinkingFn).