@Josh mentioned in his answer that
The best solution since your directiveB
-like components are expected to be used within directiveA
components is to use require
.
I've been toying with this and I believe a controller on directiveA
is the only solution (so +1 Josh). Here's what the scopes look like using the OP's fiddle:

(Reverse the brown arrow and you have $$previousSibling instead of $$nextSibling.)
Other than $$previousSibling
, scope 004 has no path to isolate scope 003. Note that scope 004 is the transcluded scope that directiveA
creates, and since directiveB
does not create a new scope, this scope is also used by directiveB
.
Since the object you wish to share with directiveB
is being created in directiveA
's controller, we also can't use attributes to share data between the directives.
Creating a model inside a directive, and then sharing that model to the outside world is rather atypical. Normally, you'll want to define your models outside your directives and even outside your controllers (listen for a few minutes to Misko). Services are often a good place to store your models/data. Controllers should normally reference the parts of the model(s) that need to be projected into the view that they are associated with.
For simplicity, I'm going to define the model on a controller, then the directives will both access this model the normal way. For pedagogical purposes, directiveA
will still use an isolate scope, and directiveB
will create a new child scope using scope: new
as in @Josh's answer. But any type (isolate, new child, no new scope) and combination will work, now that we have the model defined in a parent scope.
Ctrl:
$scope.model = {value: '#33ff33', checkedState = true};
HTML:
<div ng-controller="NoTouchPrevSibling">
<div data-directive-a data-value="model.value" data-checked="model.checkedState">
<div data-directive-b></div>
</div>
For other pedagogical reasons, I opted to pass directiveA the two model properties as separate attributes, but the entire model/object could also have been passed. Since directiveB will create a child scope, it doesn't need to pass any attributes since it has access to all of the parent/controller scope properties.
Directives:
app.directive('directiveA', function () {
return {
template: '<div>'
+ 'inside parent directive: {{checkedState}}'
+ '<input type="checkbox" ng-model="checkedState" />'
+ '<div ng-transclude></div>'
+ '</div>',
transclude: true,
replace: true,
scope: {
value: '=',
checkedState: '=checked'
},
};
});
app.directive('directiveB', function () {
return {
template: '<div>'
+ '<span>inside transcluded directive: {{model.checkedState}}</span>'
+ '<input type="text" ng-model="model.value" />'
+ '</div>',
replace: true,
scope: true
};
});
Scopes:

Note that directiveB's child scope (006) inherits from directiveA's transcluded scope (005).
After clicking the checkbox and changing the value in the textbox:

Note that Angular handles updating the isolate scope properties. Normal JavaScript prototypal inheritance gives directiveB's child scope access to the model
in the controller scope (003).
Fiddle