AngularJS combining the use of two custom directives with shared scope - angularjs

I have two different custom directives, both having an isolated scope. Is there a way to use both directives on the same element without getting:
Error: Multiple directives [...] asking for isolated scope on ...
I thought that they would share a common scope by doing so but it appears it won't (as I get this error)...
Thanks
Tom

OK, I've workarounded that issue by using the same controller for my both directives, allowing them to share the scope different from the parent scope...
I'm still interested in any suggestion on that subject.

There's a summary of how directive scopes can be combined in the reference to the $compile method.
The main points are that isolate scopes are never shared, and that an element can have at most one scope attached to it. If your directives use a child scope instead, then it will be shared between both directives.
no scope + no scope => Two directives which don't require their own scope will use their parent's scope
child scope + no scope => Both directives will share one single child scope
child scope + child scope => Both directives will share one single child scope
isolated scope + no scope => The isolated directive will use it's own created isolated scope. The other directive will use its parent's
scope
isolated scope + child scope => Won't work! Only one scope can be related to one element. Therefore these directives cannot be applied
to the same element.
isolated scope + isolated scope => Won't work! Only one scope can be related to one element. Therefore these directives cannot be applied
to the same element.

Well, I think Angular gives you the choice between working with a parent scope and communicating between directives.
You can achieve the latter one by adding an interface in the "master" directive by adding a controller function which the "slave" directive consumes. The slave explicates the dependency via require: '^masterDirective' and can use its interface in the link function.
See the official explanation with a nice example: https://docs.angularjs.org/guide/directive#creating-directives-that-communicate

Related

Scope in Angularjs

I was trying to understand scope in angularjs.
Say while registering a directive in angularjs if we dont provide any scope as the property of the object, what is the scope of the object then?
For example consider the following code:-
app.directive("kid", function() {
return {
restrict: "E",
template: '<input type="text" ng-model="chore"> {{chore}}'
};
});
Now say if i have 2 elements in my html:-
<kid></kid>
<kid></kid>
So how do above end up sharing the same scope? I am not able to find convincing answer yet.
Yes, As you didn't declared any scope option of directive, it will share the same scope.
Here is Demo Plunkr
Now come to the point, what is scope object?
scope object in Angular is nothing having context information and that will available on html, can also be utilized to provide two way binding. Basically scope is binded with some controller.
When things comes to directive scope, if you didn't mention scope property inside directive, that means directive shares the scope of the controller where the directive element has been placed.
To make them treated as a different scope for each directive you could create an an directive with an isolated scope, which can be defined using scope: {} inside a directive, when you define a scope: {} inside a directive, it creates an isolated child scope which is not prototypically inherited from the parent scope using $scope.$new(true) method.
Plunkr with isolated scope
Your question is about scope inheritance and isolate scope.
If you do declare a scope property on a directive object then the directive has its own isolate scope.
If you don't declare a scope property on your directive object the directive inherits the scope of the scope it was instantiated in.
So with your definition of the kid directive that doesn't declare an isolate scope the kid directives in the code example below both inherit the scope of the controller that they are instantiated in.
<div ng-controller="myCtrl">
<kid></kid>
<kid></kid>
</div>
Scope is an object that refers to the application model. It is an execution context for expressions. Scopes are arranged in hierarchical structure which mimic the DOM structure of the application. Scopes can watch expressions and propagate events.
Scope characteristics
Scopes provide APIs ($watch) toenter image description here observe model mutations.
Scopes provide APIs ($apply) to propagate any model changes through
the system into the view from outside of the “Angular realm”
(controllers, services, Angular event handlers).
Scopes provide context against which expressions are evaluated.
For example {{username}} expression is meaningless, unless it is evaluated against a specific scope which defines the username property.Scope is the glue between application controller and the view.

What is Diff between scope and Isolate scope

While implementing directive I came across isolate scope , I am having Confusion why we have to Use isolate scope instead of scope.
When using an isolated scope, the directive's scope does not prototypically inherit from its parent. The directive has no access to the parent scope. This gives you the highest encapsulation. You should use an isolated scope, whenever you're designing reusable components.
Directives have access to the parent scope by default. For example, the following directive relies on the parent scope to write out a user object’s name:
angular.module('myDirective').directive('sharedScope', function () {
return {
template: 'Name: {{user.name}}'
};
});
The problem with this code is that you need to have an information about the parent scope, thus if the parent scope changes? The directive will become not usable anymore. That's when isolated scope comes in handy. Therefore isolated scope is used whenever directive is designed to be reusable. These are some good blog post which explain in depth the topic
AngularJS Directives, Using Isolated Scope with Attributes
Angularjs Sticky Notes
Creating Custom AngularJS
directives

When does angularjs create new scopes

angularJS seems to create new scopes, in that there are parent scope, child scope, and sibling scope.
What determines when a new scope is created? For example, if I use ng-inspector to view the scopes present, there is the $rootScope, and also other scopes, but it is not obvious to me what the other scopes correspond to, nor is it clear to me when these other scopes are created/destroyed. I believe they are created/destroyed because the $id changes. Changes occur if I navigate around and press forwards/back.
Angular creates new scope for every instantiated controller on that part of DOM.
Angular also creates scope for every directive (except scope:false, that means for directives with isolated scope, and scope:true). A scope is also created for built in directives such as ng-repeat where it creates scope for every repeated item.
Also when you use ng-if directive it can remove and add parts of the DOM and when it adds it all the controllers and directives will add their scopes again.
Angular's scope tree pretty much will mirror the dom tree. Directives can create new scope. Not just your directives, but also built in Angular directives like ng-if. It's a bit of an in depth topic...
Here is a blog post that explains things more in depth.
Hope that helps!

Angular 1.2 no longer allows multiple isolated scope directives on same element?

I have some code in an Angular project that use two separate directives with isolated scope. They do not need to share scope, simply exist on the same element. They both alter the DOM in slightly different ways, and importantly bind to values passed as arguments.
This worked in 1.0, however Angular 1.2 now generates an error when attempting to do this
Multiple directives asking for new/isolated scope
Based on the projects git history appears Angular 1.2 changes behaviour to keep two isolated directives on the same element separate. This is a good thing, and it works correctly when putting two 'Attribute' directives on the same element.
i.e.
<div my:directive="myDirectiveData" my:other-directive="myOtherDirectiveData" />
works as you would expect.
however
<my:directive my:directive-data="myDirectiveData" my:other-directive="myOtherDirectiveData" />
Throws the above error. (Multiple directives asking for new/isolated scope)
In this scenario I would have expected each directive to still exist in parallel with their own unshared isolated scope.
Is this still possible in Angular 1.2?
Summary of what happens when multiple directives are defined on the same element:
Scenario directive #1 directive #2 Result
1 no new scope no new scope Both directives use the controller's scope.
(This should be obvious.)
2 new scope new scope Both directives share one new child scope.
3 new scope no new scope Both directives share one new child scope.
Why does dir #2 use the child scope?
This seems odd to me.
4 isolate scope no new scope Angular v1.0: both directives share the
isolate scope.
Angular v1.2+: dir #1 uses the isolate scope,
dir #2 uses the controller's scope.
Note that the following scenarios are not allowed (Angular throws an error):
Scenario directive #1 directive #2
5 isolate scope new scope
6 isolate scope isolate scope
You can't have multiple directives asking for isolate scope on the same element.
I think your problem may be caused by this unresolved issue in angularjs.

Element does not get isolate scope if highest priority directive does not have one

Is it correct that angular does not create an isolate scope for a element that has two directives on it where the highest priority directive does not have an isolate scope and the lower priority directive does?
I have the following plunker that has 2 directives and a controller:
http://plnkr.co/edit/zEnMH6h0ILURHSgx0DLX?p=preview
If you open up the console, you can see the logs of the scopes of the directives and controller. The noIsoScope directive does not have a isolate scope and has a priority of 1. The isoScope scope directive has an isolate scope but a priority of 0. When I use each directive independently, everything works as excepted. When I use both of them together, the isoScope directive shows that is it using the controller scope (since based on the logs, it has the same $id) instead of its own.
Do I have to make sure that whenever I am using multiple directive on an element, if one of them has an isolate scope, that it has to have the highest priority?
Short answer yes.
It doesn't make sense to have 2 directives require both an isolate scope AND a parent scope. The idea would be to think about how directive can work with each other. How would the parent scope directive work correctly if the scope it has is the isolate scope?
I guess the angular team decided to not give a warning in this situation(could be a bug).
if the lower priority requires a isolate scope that means it has a strict requirement of data from parent scopes
if the higher priority doesn't require a scope that means it will inherit the parent scope and potentially use that data in the template.
This is a catch 22 situation:
It doesn't make sense that the non isolate directive use a isolate scope since it might depend on the fact that it's not isolate.
At the same time the isolate directive most likely depends on the fact that it's isolate.
From Igor Minar, he's talking about multiple isolate scopes but it's the same issue basically:
My suggestion is to use isolate scopes when you are creating reusable components that are backed by a template. If you want to compose multiple directives together, you should design them in a way that make one directive the main one (with the template) and the other directives are just helper directives (sort of like traits or mixins in some programming languages).

Resources