AngularJS directive with method called from outside
Solution 1
I found my issue.
From the angularJS documentation on directives I was looking into the transclude
option since that states:
What does this
transclude
option do, exactly? transclude makes the contents of a directive with this option have access to the scope outside of the directive rather than inside.
I combined transclude=false
with the controller
function since that exposes the method, again from docs:
Savvy readers may be wondering what the difference is between link and controller. The basic difference is that controller can expose an API, and link functions can interact with controllers using require.
However what I missed completely was that I isolated scope within my directive. From docs:
What we want to be able to do is separate the scope inside a directive from the scope outside, and then map the outer scope to a directive's inner scope. We can do this by creating what we call an isolate scope. To do this, we can use a directive's scope option:
So even if you use transclude=false
and the controller
function you'll still fail to expose methods if you use isolated scope! Lesson learned!
While figuring out what went wrong I also made a fiddle for better understanding: http://jsfiddle.net/qyBEr/1/
html
<div ng-app="directiveScopeExample">
<div ng-controller="Ctrl1">
<p>see if we can trigger a method form the controller that exists in the directive.</p>
<ul>
<li><a href="#" ng-click="methodInController()">Method in Controller</a></li>
<li><a href="#" ng-click="methodInDirective()">Method in Directive</a></li>
</ul>
<simple-directive/>
</div>
</div>
javascript
angular.module('directiveScopeExample', [])
.controller('Ctrl1', function Ctrl1($scope) {
$scope.methodInController = function(){
alert('Method in controller triggered');
};
})
.directive('simpleDirective', function(){
return {
restrict: 'E',
transclude: false,
controller: function($scope){
$scope.methodInDirective = function(){
// call a method that is defined on scope but only within the directive, this is exposed beause defined within the link function on the $scope
$scope.showMessage('Method in directive triggered');
}
}
// this is the issue, creating a new scope prevents the controller to call the methods from the directive
//, scope: {
// title: '@'
//}
, link: function(scope, element, attrs, tabsCtrl) {
// view related code here
scope.showMessage = function(message){
alert(message);
}
},
//templateUrl: 'some-template-here.html'
};
})
Solution 2
Calling private methods inside directive's link function is very simple
dropOffScope = $('#drop_off_date').scope();
dropOffScope.setMinDate('11/10/2014');
where
$('#drop_off_date') - jQuery function
setMinDate() - private function inside directive
You can call directive function even from outer space.
Solution 3
By default the scope on directive is false meaning directive will use the parent's scope instead of creating a new one. And hence any function or model defined in the directive will be accessible in the parent scope. Check out this.
I think your problem can be solved as follows:
angular.module('directiveScopeExample', [])
.controller('Ctrl1', function Ctrl1($scope) {
$scope.methodInController = function(){
alert('Method in controller triggered');
};
})
.directive('simpleDirective', function(){
return {
restrict: 'E',
scope: false,
link: function(scope, element, attrs, tabsCtrl) {
// view related code here
scope.showMessage = function(message){
alert(message);
}
},
//templateUrl: 'some-template-here.html'
};
This approach might be an issue in case you want to create reusable directives and you are maintaining some state/models in your directive scope. But since you are just creating functions without side-effects, you should be fine.
hcpl
Professional Java Software Engineer and Android Developer with a passion for Photography
Updated on November 03, 2020Comments
-
hcpl over 3 years
I created a directive with a method that should be called from other elements that are not part of the directive. However it looks like this method is not exposed.
Some example jade code to clarify:
//- a controller for the view itself div(ng-controller="someController") //- this is part of the view itself, not within the directive div(ng-repeat="element in elements") div(ng-click="methodFromDirective(element)") click element {{$index}} to trigger directive //- this is the directive div(some-directive)
The
someController
isn't too important here I think. It has methods but NOT themethodFromDirective(element)
one. ThemethodFromDirective(element)
is a method that exists only in the directive.If I make a directive and put some logging on creation I can clearly see it's created. However the
methodFromDirective(element)
method isn't exposed so the calls aren't properly triggered.The
methodFromDirective(element)
itself will only work on elements from within the directive's template.some coffeescript to show the definition of the the directive (ignore indentation errors here):
'use strict' define [], () -> someDirective = () -> restrict: 'A' scope: { show: '=' } transclude: false templateUrl: 'someTemplateHere.html' controller = ($scope) -> # exposing the method here $scope.methodFromDirective(element)-> $scope.theMethod element link = (scope, element, attr) -> # this is logged console.log "init someDirective" # triggering this method form outside fails scope.theMethod = (element)-> console.log "method triggered with element", JSON.stringify(element)
-
stephen776 about 9 yearsis there a way to call the directive methods from exising JS? i would like to just be able to call
methodInDirective()
from any JS on the page -
enpenax almost 9 yearsJust making sure: the reason why this works is because the directive uses the parent's scope as you don't define an isolated scope. You do not even need the controller declaration in the directive and can move the definition of
methodInDirective
straight to the link function, too. So basically your directive adds methods to the parent's scope. not sure how that is advisable tho :/ -
The Red Pea over 7 years"even from outer space"
-
The Red Pea over 7 yearsI don't see how
transclude
is relevant here. This example works whethertransclude
is true or false, right? -
695Multimedia over 7 yearsI get "scope is not a function" on my jQuery object.
-
Robert Henderson about 7 yearsI would recommend only using this strategy if you are using a third-party directive that you cannot edit. Otherwise, you should edit your directive to make accessing its methods available elsewhere. If you use this strategy, you should use angular.element(), not the jQuery $() selector.
-
Somnium about 5 yearsThis works only in debug mode, so you cannot use this.