Accessing parent scope in isolated directive - angularjs

I'm building click to edit directives, but have issues understanding how to access parent scope in an isolated directive.
Example: http://jsfiddle.net/ADukg/3591/
scope: {},
It works if I "unisolate" the scope removing scope: {}; but need the isolated scope.
UPDATE:
Done it adding
controller: 'FormCtrl',
To the directive. See http://jsfiddle.net/ADukg/3601/

You could use the $parent property on the isolate scope to get direct access to the parent scope, but normally you'll want to use attributes to specify which parent scope properties the directive needs to do its work.
If you need to change the parent scope properties in the directive, bind with = (two-way objects). If you only need the string values of the parent scope properties in the directive, bind with # (one-way strings).

The given solution won't work if you pass an attribute with primitive type like 'string', 'long' .... etc
The two-way binging works only with object.
Every scope object contains a special property called $parent which refers to its parent scope. The isolated scope also has a $parent property. But it refers to the enclosing controller/directive's scope.
To make it work with primitive attributes: you could bind your directive template to a controller. This will expose your directive to its parent and you can access by $parent.
Second solution is to not make an isolate scope (but i don't think it's your goal).

Related

angular directive automatically re-instantiated when scope change

Many of my directive (soon to become components) takes their scope from variables set by other directives. Currently in each directive I have to watch my scope to know if it has changed which seems to complicate the code unnecessarily. So I started using ng-if="vm.ready" on my tag to reinstantiate the directive when I need it to. But then the management of that state is left outside of the directive which is harder to maintain.
I am wondering if angular provide such a mechanism when if the scope of your directive change then it will at least reinstantiate your directive controller.
Thanks
You can probably use $onInit()
After the controller is instantiated, the initial values of the isolate scope bindings will be bound to the controller properties. You can access these bindings once they have been initialized by providing a controller method called $onInit, which is called after all the controllers on an element have been constructed and had their bindings initialized.
https://github.com/angular/angular.js/blob/master/src/ng/compile.js#L250

Angular scope modification inside transcluded content

Angular: Can anyone explain why transcluded content in a directive can only update objects on the scope - not variables directly on the scope. Is it just because the object and functions are ref type in javascript and why does the binding work one way and ... why does the binding break after the update inside the transcluded content (see plunker samples)
-Plunker sample - variable on scope vs object on scope
Working -Plunker sample - variable on scope
Transcluded content can also update parent's scope properties
Transcluded content is like any other content, therefore if you followed the dot.rule you'll be able to update the parent scope properties you want. Always follow the dot.rule and refactor your logic to make sure everything is done in the angular way.
Directive scope types
Directives in angular prior to 2.0 version accept several types of scopes, the scope can be true, which creates a new one and inherits parent's properties; false, which does not create a new scope, but still inherit parent's properties; or {} which is known as an isolated scope, this creates a new scope with zero properties, it keeps only the properties you declare.
One-Way vs Two-Way data binding
Angular uses both, one-way and two-way data binding. For example, two-way data binding occurs when you use the ng-model directive, whenever you update the model, the view will reflect those changes and viceversa. On the other hand, one-way data binding occurs when you use the interpolation {{some.property}}
The two-way data binding should not break if you are using the dot.rule. That's how prototypical inheritance works after all.
Check out this Pen to illustrate everything said in this answer.

Why are AngularJS isolate scopes not attached to the directive root element (when using replace)?

When using the replace flag on a directive, normal scopes get attached to the root element of the template and the element gets appended with a "ng-scope" class.
When a directive uses an isolate scope the root element of the template still gets appended with a scope class: "ng-isolate-scope", but the isolate scope itself is attached NOT attached to the node. Why this behavior?
It is of interest to me because it also appears to mess with the expected behavior of a template that uses ng-if in the root element of a template. It causes the template transclude from the external scope instead of transcluding from the local isolate scope of the directive.
here is an example of a simple directive with an isolate scope and replace set to true. If you note the console log you will see that the root element of the directive is not bound to the directive's scope, only the child element is.

Directive = or =attr not bi-directional

= or =attr - set up bi-directional binding between a local scope
property and the parent scope property of name defined via the value
of the attr attribute. ... Any changes to parentModel will be
reflected in localModel and any changes in localModel will reflect in
parentModel.
This is from Angular docs, and I have read a few post that say you DON'T get bi-directional binding when creating isolated scopes with directives. I am finding it difficult to understand. I want to create a widget, passing in state but I also want to be able to bind that state to other directives in the parent scope.
From my experiments you can't make a change to scope in the directive and pick up the change in it's parent controller/ other directive. Is this correct?
Yes and no an isolate scope (e.g. you've added a scope: {} to your directive) in angular is just that, an individual scope that is not linked in the prototypal inheritance chain. This means that by default and changes you make to the scope in the directive will not be reflected back into the scope of parent elements to this directive.
The '=' locals type in the scope creation sets up up a visible binding to the parent scope. Then changes to the isolated scope variable will be reflected back. Make sure your changes are being recognized by the locals scope in your directive or nothing will propagate up (e.g. try watching/$watch the locals variable to ensure a change is occurring in the directive, if not you may need to $apply depending on how you've bound within your directive).

AngularJS - nested directives without transclude?

Accompanying plunker.
I have an attribute-level custom directive in a div. The directive has an isolated scope. Inside my div I have other directives that expect to be in the scope of the parent.
The issue is that the directives inside my div have access only to the isolated scope, not to the parent scope. I understand why, but I'm not clear on how to solve it cleanly.
I know that I can use transclude to solve this (see plunker) but this feels very sloppy. I have no need for a template, but I'd have to create one just for transclude to work, and transclude seems to be the only way to ensure that my nested directives have access to the correct scope.
Is there an alternative, cleaner way to do this?
To head off some possible questions:
I'm using an attribute-level directive instead of an element-level to make things easier for IE
I'm using an isolated scope because it's a best practice - I don't want to hose my parent scope by accident, and I want the directive to be portable.
I'm really not sure what you're trying to do.
But what you're actually doing is leveraging bidirectional binds on an isolated scope for ill-effect. It almost seems unrelated to your question.
Anyhow... here is an update to your plunker
Basically what was happening is inside of your isolated directive you need to use whatever name you've assigned in your scope declaration, in this case toggleOn().
however if you want to you can do this. Basically just call $parent.colorToggle().
You can decide if this is "less sloppy" than transcluding:
<button ng-click="$parent.colorToggle()">Inside</button>
Isolate scopes have access to the parent scope via a $parent property. Although an isolate scope does not prototypically inherit from its parent scope, Angular still maintains a hierarchy via $parent and $$childHead and $$childTail.

Resources