Angular Directive to Directive access - angularjs

How can I access scope value in first directive controller to second directive controller.
So What I mean is if I have $scope.Hello= "Hello"; in first directive I want to access this in my second directive controller.
How can I do that. I tried with broadcast but I know that only between parent and child access. Here my scenario is child and child access.

In the link of first directive, call 2nd directive and pass it as attribute.
link: function (scope, element, attrs) {
angular.element(document.body).append($compile('<my2ndDirectivehello="' + scope.hello+'"></my2ndDirective'>
};

Related

Directive to directive communication?

I have a page with two directives.
1. Directive that lists items , these items have a property on them call url
2. a directive on the same page that accepts url and displays it
What I want to do is, when the user clicks on one of the items in the first directive, to send that item.url to the 2nd directive as a parameter ?
What is the best practices for this scenario ?
Few ways to achieve this:
Common Parent Scope Property
Specifically the parent controller encompassing both of your directives has a property for storing the selected URL.
Then this property is passed into both of your child directives.
e.g.
<parent>
<directive-one data-selected-url="selectedUrl"></directive-one>
<directive-two data-url-to-display="selectedUrl"></directive-two>
</parent>
Broadcast Events
Have directive one broadcast an event on a scope that is shared by both directives.
e.g.
in directive one:
$scope.$broadcast('urlSelected', selectedUrl);
in directive two:
$scope.$on('urlSelected', function(event, selectedUrl) { ... });
NOTE: as I mentioned the scope needs to be a shared scope between the two directives, as broadcast sends the event DOWN the scope chain ($emit sends it up).
Accessing Parent Controllers
You could store the selected Url in a parent directive and have both children require that directive. They would then both be able to set/get the property from the parent directive.
e.g. in the child directives:
require: 'parentDirective'
link: function (scope, element, attrs, parentCtrl) {...}

When does transclusion take place in the compilation/linking process of a directive's setup?

I'm writing a custom directive that uses transclusion. I need to make modifications to the transcluded DOM content AFTER the transclusion has taken place....would I want to do that in the post-link or in the controller or ... the link...? I don't know where transclusion falls in the order of those things happening, so I don't know how to ensure my JS is executed after the transclusion has taken place.
The transclusion takes place during the compilation phase. Angular's $compile service goes over the DOM, and if a directive has transclusion enabled, Angular extracts the contents of the element (if transclude: true, or the element itself - for transclude: 'element'), compiles them, and makes the compiled content available in the transclusion function, bound to the transclusion scope.
So, the order of execution would be:
Angular transcludes the contents and compiles it: compile functions of the transcluded content directives execute
compile function of the directive executes - returns pre- and post-link functions
controller function of the directive executes
pre-link function of the directive executes
post-link function of the directive executes.
You may decide to execute the transclude function in the post-link function. As soon as you do,
controller, pre-, and post-link functions of the transcluded content directives execute
transclude function is available at step #3-#5, and when invoked, it provides a fresh copy of the transcluded element to the cloneAttachFn, which you provide as a parameter to the transclude function:
link: function(scope, element, attrs, ctrls, transclude){
transclude(scope, function cloneAttachFn(clone){
// you can do DOM manipulation of the clone instance here
});
}
Note, that the DOM manipulation in the cloneAttachFn would apply to an instance of the transcluded DOM - not to the pre-compiled DOM template.

AngularJS: Directive to Controller communication with scope.apply not working

I have a MainController and a nested Directive. I'm looking at this example to see how the communication works between controllers and directive, but mine doesn't seems to work.
Basically, I want to call a main controller scope function from a custom directive (button empty cart). See the plunkr example below.
Plukr: http://plnkr.co/edit/82STLkKxBK6htTnmnqlu?p=preview
Whenever I do console.log(scope.$apply("emptyCart()")), it's undefined for some reason.
Note: I'm trying to avoid $rootScope.broadcast as much as possible...
You're using isolate scope for the parent directive, so the child directive does not have access to the scope of the controller.
In order to provide the child directive with access to that scope function while maintaining isolation of the parent, you can add that function as a scope: { ... } property on the parent directive:
scope: {
...
emptyCart: '='
}
and set the function name to the corresponding attribute on the parent directive's view declaration:
<div ... data-show="showPopup" empty-cart="emptyCart"></div>
Then you can skip all of the workarounds you've attempted to employ in your Plunker, and just set an ng-click on the child directive in order to fire the controller function:
sHTML = "<button ... ng-click='emptyCart()'>Empty cart</button>";
Demo

scope.$watch not invoked by AngularJS directive

I have the following link function in an AngularJS directive:
link: function(scope, iElement, iAttrs) {
scope.$watch('name', function(newVal){
if(newVal){
console.log(newVal);
}
}, true);
}
The full fiddle is located here: http://jsfiddle.net/balteo/K4t7P/55/
I am trying to figure out why the $watch function is not invoked when a user changes the name variable in the textarea.
You are creating a new scope when you write this on your directive
scope: {
name: '='
}
Just remove it and all will work well
Fiddle
Explanation
About the scope attribute, in the docs, we read:
If set to {} (object hash), then a new "isolate" scope is created. The 'isolate' scope differs from normal scope in that it does not prototypically inherit from the parent scope. This is useful when creating reusable components, which should not accidentally read or modify data in the parent scope.
= 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. If no attr name is specified then the attribute name is assumed to be the same as the local name.
Note that for two-way data-binding, is expected that you pass your model as attribute.
When you do this (write your model as an attribute) it works like a charm (check this fiddle).
But you are passing your attribute via ng-model. It's already available on the scope of the directive. When you create a new scope, you are actually creating a child scope at your controllers scope and setting it to your scope parameter in the link function. In fact, if you watch the $scope.$parent.name it will work as well (check this fiddle).

How to access variable defined in directive to controller?

I have to access variable defined in directive and access it in the controller using angularjs
directive :
app.directive('htmlData', function ($compile) {
return {
link: function($scope, element, attrs) {
$(element).on('click', function() {
$scope.html = $compile(element)($scope).html();
});
return $scope.html;
}
};
});
and use $scope.html in controller.
Since you are not creating an isolate scope (or a new scope) in your directive, the directive and the controller associated with the HTML where the directive is used are both using/sharing the same scope. $scope in the linking function and the $scope injected into the controller are the same. If you add a property to the scope in your linking function, the controller will be able to see it, and vice versa.
As you set the variable in the $scope, all you got to do is to bind to it normally. In your case, osmehting like:
<div html-data>{{html}}</div>
Maybe you're not seeing the update because it lacks a $scope.$apply().
Anyway, let me say that I see two problems on you code. First of, you could use ng-click directive to attach click events to your HTML.
Secondly, why would you recompile your HTML every time? There is almost no need for that. You may have a big problem, because after first compilation, your template is going to be lost, so recompiling will render it useless.
If you need to get the element, you can inject $element.

Resources