Need to call parent function from nested directive angularjs - angularjs

Below is my flow of application. I wanted to access the parent controller function from the child directive
<div ng-controller="ParentController">
<first-directive></fist-directive>
</div>
in First Directive another directives loading
<div ng-controller="FirstController">
<second-directive></second-directive>
</div>
from second-directive calling parent function
<div ng-controller="SecondController">
<a ng-click="ParentFunction(2342)"></a>
</div>
ParentFunction() is available in Parent Controller. I wanted to call the function from second-directive.
ParentController-->FirstDirective-->SecondDirective
How to call the parent function from SecondDirective for my scenario?

Make the first directive and second directive to inherit the parent scope(don't define scope property for them). If they are isolated scope then they can not access parent scope.
Then in the second directive do this -
<div ng-controller="SecondController">
<a ng-click="$parent.$parent.ParentFunction(2342)"></a>
</div>
EDIT:
If the directives have isolated scope as OP has commented here, then you have to pass the function to directive, so your code becomes like this
<div ng-controller="ParentController">
<first-directive function-to-call="parentFunction()"></fist-directive>
</div>
<div ng-controller="FirstController">
<second-directive function-to-call="functionToCall()"></fist-directive>
</div>
<div ng-controller="SecondController">
<a ng-click="functionToCall(2342)"></a>
</div>
And the in the directive you have to have some values to scope like this
first Directive
scope: {
functionToCall: '&'
}
Second Directive
scope: {
functionToCall: '&'
}

Related

How to share directive scope with transcluded elements?

I am trying to create a directive with transclusion. Issue is the scope of transcluded part is different from that of the directive scope.
I have tried it on plnkr here is the link - http://plnkr.co/edit/vDfXs9zyfAngPqmFCiZR?p=preview
I want the directive to have isolated scope yet be able to switch among the tabs, based on which button is clicked.
index.html
<maple-multistep-form steps="steps">
<span>transcluded scope - {{selection}}</span>
<div ng-switch="" on="selection">
<!-- First Step -->
<div ng-switch-when="Step 1: Team Info">
<ng-include src="'step1.html'"></ng-include>
</div>
<!-- Second Step -->
<div ng-switch-when="Step 2: Campaign Info">
<ng-include src="'step2.html'"></ng-include>
</div>
<!-- Third Step -->
<div ng-switch-when="Step 3: Campaign Media">
<ng-include src="'step3.html'"></ng-include>
</div>
</div>
Try passing the 'selection' to the directive.
http://plnkr.co/edit/23QO2UGvKwwXK7PRo2bJ?p=preview
<maple-multistep-form steps="steps" selection="selection">
and inside
scope: { //comment scope to make the directive have shared scope, this makes the directive work fine
steps: '=',
selection: '=?'
},

Prevent triggering Angular Material md-swipe-left/md-swipe-right directive's function on parent element

I have a parent element that fills 100% of page height and several child elements inside it. Swipe-right on the parent toggles side menu, but I want to prevent this function and trigger childAction() when I swipe-right on it's child.
<div id="parent" md-swipe-right="toggleSideMenu()">
<div id="child" md-swipe-right="childAction()">
....
</div>
</div>
The md-swipe-right like all other event directives provides $event as a local.1
In your HTML include $event as an argument to your function.
<div id="parent" md-swipe-right="toggleSideMenu()">
<div id="child" md-swipe-right="childAction($event)">
....
</div>
</div>
In your controller invoke the stopPropagation() function.
$scope.childAction = function (event) {
event.stopPropagation();
});
For more information on $event see, AngularJS Developer Guide -- expressions -- $event

how to have unique scope in ng-repeat in angularjs

Is it possible for me to have multiple array for $scope?
i have a list of div with child scopes that is generated from a parent scope in ng-repeat. How can i have the scope variable individually unique?
I am generating a list of ng-repeat in another ng-repeat.
<div ng-repeat="" ng-init="hide=true" ng-click="hide=!hide">
<div ng-hide="hide" ng-init="childhide=true" ng-click="childhide=!childhide">
<div ng-repeat="" ng-init="childhide" ng-hide="childhide">
<div>{{ variable }}</div>
</div>
</div>
</div>
How can i have the variable unique? Coz each time when i click on either one div, all div with childhide variable will show. Anyway to make them behave individually?
Thanks.
To get a new $scope for each div, the first ting that comes to mind is to create another directive and specify which type of scope you want.
<div class="container">
<div ng-repeat="item in items"></div>
</div>
will become:
<div class="container">
<inner-directive ng-repeat="item in items"></inner-directive>
</div>
then in inner-directive:
app.directive('innerDirective', function () {
return {
restrict: 'E',
template: '<div></div>', // this replaces what you had before
scope: {}
};
});
This will create an isolate scope, which does not inherit properties from it's parent.
There are a couple of other scope options but i cant remember off the top of my head what each one does. Easy to read in the docs though.

Directive doesn't work when I which the version of Angular to 1.0.1 to 1.2.27

The following could be run in demo here.
this is html:
<div ng-controller="MyCtrl">
<h2>Parent Scope</h2>
<input ng-model="foo"> <i>// Update to see how parent scope interacts with component scope</i>
<br><br>
<!-- attribute-foo binds to a DOM attribute which is always
a string. That is why we are wrapping it in curly braces so
that it can be interpolated.
-->
<my-component attribute-foo="{{foo}}" binding-foo="foo"
isolated-expression-foo="updateFoo(newFoo)" >
<h2>Attribute</h2>
<div>
<strong>get:</strong> {{isolatedAttributeFoo}}
</div>
<div>
<strong>set:</strong> <input ng-model="isolatedAttributeFoo">
<i>// This does not update the parent scope.</i>
</div>
<h2>Binding</h2>
<div>
<strong>get:</strong> {{isolatedBindingFoo}}
</div>
<div>
<strong>set:</strong> <input ng-model="isolatedBindingFoo">
<i>// This does update the parent scope.</i>
</div>
<h2>Expression</h2>
<div>
<input ng-model="isolatedFoo">
<button class="btn" ng-click="isolatedExpressionFoo({newFoo:isolatedFoo})">Submit</button>
<i>// And this calls a function on the parent scope.</i>
</div>
</my-component>
</div>
And this is js:
var myModule = angular.module('myModule', [])
.directive('myComponent', function () {
return {
restrict:'E',
scope:{
/* NOTE: Normally I would set my attributes and bindings
to be the same name but I wanted to delineate between
parent and isolated scope. */
isolatedAttributeFoo:'#attributeFoo',
isolatedBindingFoo:'=bindingFoo',
isolatedExpressionFoo:'&'
}
};
})
.controller('MyCtrl', ['$scope', function ($scope) {
$scope.foo = 'Hello!';
$scope.updateFoo = function (newFoo) {
$scope.foo = newFoo;
}
}]);
This should be a good example for three kinds of scope binding in directives.However, it just doesn't work when I try to switch a higher angular version - (1.2.27). I suspect the shadow of the inherited scope within the directive, but I'm not sure of it.
This isn't going to work the way you expect. Isolated Scopes are created and provided to the Link, Compile, and Template portions of a Directive. However, the HTML within the Element itself is not actually part of the Directive. Those HTML portions are still bound to the parent $scope. If you have a tendancy to name your isolated scope objects the same, you may have just been working against the $scope unintentionally and not noticed any ill effect. If your HTML was in a Template rather than inside the Element, it would access the isolate scope.
As an example, in the HTML that is inline in the Element, you can call updateFoo(), but that would not be possible from inside a Template

Scope issues when declaring controller for a modal in AngularUI/Boostrap

What I'm trying to do is have a custom directive inside a modal that just returns a list of files. The issue I'm having is that the scope seems to be different depending on how I declare my controller on my modal. Inside my modal I have a custom directive with an isolated scope that just returns a list of selected files. The first method I have is declaring it as a parameter in the modal creation.
$scope.openModal = function(){
uploadDialog = $modal.open({
templateUrl: 'modal.html',
size: 'lg',
controller:'modalController'
});
The second method I tried is declaring it at the top of the div of the modal template so I had to make a new div and wrap the whole modal template.
The second method returns everything fine, but the first method doesn't return it at all. I did notice while debugging that the "this" property has the value selectedFiles. Why does the two method yield different results?
Method 1 Plunker: http://plnkr.co/edit/6FTQq7fT49lETR5TEzaF?p=preview
Method 2 Plunker: http://plnkr.co/edit/QWnbH8GZArMgYqgcQ8L9?p=preview
To answer your question, please first see my comments in the DOM elements after a modal template has been compiled below:
Method 1:
<!-- Method 1 controller's scope is here, it is the same as modal's scope -->
<div class="modal fade in ng-isolate-scope">
<div class="modal-dialog modal-lg">
<!-- This ng-transclude create a new scope for each its children elements -->
<div class="modal-content" ng-transclude>
<div class="modal-header ng-scope">
<h3 class="modal-title">Test</h3>
</div>
<!-- The selectedFiles will be stored in this scope, not the controller scope above. -->
<div class="modal-body ng-scope">
<upload-dir files="selectedFiles" class="ng-isolate-scope">
<div>{{selectedFiles}}</div>
<button ng-click="clickHere(selectedFiles)">click here</button>
<div>From $scope: <input type="text" ng-model="test"></div>
<div>From parameter: <input type="text" ng-model="testParam"></div>
</div>
<div class="modal-footer ng-scope"></div>
</div>
</div>
</div>
Method 2:
<!-- The modal's scope is here -->
<div class="modal fade in ng-isolate-scope">
<div class="modal-dialog modal-lg">
<!-- This ng-transclude create a new scope for each its children elements -->
<div class="modal-content" ng-transclude>
<!-- Method 2 controller's scope is here -->
<div ng-controller="modalController" class="ng-scope">
<div class="modal-header">
<h3 class="modal-title">Test</h3>
</div>
<!-- There is no new scope created here, -->
<!-- so the selectedFiles will be stored in the controller's scope above -->
<div class="modal-body">
<upload-dir files="selectedFiles" class="ng-isolate-scope">
<div>{{selectedFiles}}</div>
<button ng-click="clickHere(selectedFiles)">click here</button>
<div>From $scope: <input type="text" ng-model="test"></div>
<div>From parameter: <input type="text" ng-model="testParam"></div>
</div>
<div class="modal-footer"></div>
</div>
</div>
</div>
</div>
As you can see, the controller's scope in Method 1 is not the nearst scope that the selectedFiles is defined, that why the $scope.selectedFiles and $scope.test are undefined.
You could workaround the issue by keeping the selectedFiles in some object before put it in scope, e.g. $scope.model.selectedFiles. Please see the plunker below for an example.
Method 1 Plunker (Modified): http://plnkr.co/edit/pP2L1ZJLxXJXgqR3QAIT?p=preview
Hope this clear things up!

Resources