Reputation: 4073
Directive
myApp.directive('vlcControls', function ($compile, $rootScope, $timeout, $window, pictureboxConstants) {
var linker = function (scope, element, attrs) {
vlcPlayerCustomTemplate = 'some html goes here';
scope.getVLC = function (name) {
if ($window.document[name]) {
return $window.document[name];
}
if ($window.navigator.appName.indexOf("Microsoft Internet") == -1) {
if ($window.document.embeds && $window.document.embeds[name])
return $window.document.embeds[name];
} else {
return $window.document.getElementById(name);
}
}
scope.doPlayPause = function (vlcPlayer, event) {
var vlc = scope.getVLC(vlcPlayer);
if (vlc) {
if (vlc.playlist.isPlaying) {
vlc.playlist.pause();
angular.element(event.target).children().removeClass('fa fa-pause font-12');
angular.element(event.target).children().addClass('fa fa-play font-12');
} else {
if (vlc.audio.mute == true) {
//do something
}
vlc.playlist.play();
}
}
}
angular.element(document.querySelector("#controls" + index)).append(element.html(vlcPlayerCustomTemplate));
$compile(element.contents())(scope);
};
return {
restrict: "E",
link: linker
};
});
Controller
myModule.controller('myModuleCtrl', function ($scope, $http, $controller, $compile) {
$compile("<vlc-controls></vlc-controls>")($rootScope);
});
What is the best way to only call specific directive
function/method doPlayPause
from controller
without using vlcPlayerCustomTemplate
html elements or any DOM
manipulations ?
Upvotes: 1
Views: 241
Reputation: 12022
Your goal is to call the directive
methods from the controller
without any DOM
manipulation and you can achieve the same with help of isolated scope
as below.
You can have an isolated scope
in your directive
as below.
scope: {
/* This is the reference object passed from the controller */
controllerRef: '='
}
Then you can pass the same from the controller
,
$scope.vlcControls = {};
$compile('<vlc-controls controller-ref="vlcControls"></vlc-controls>')($scope);
Then you can assign the methods to this object in the directive,
scope.controllerRef = scope.controllerRef || {};
angular.extend(scope.controllerRef, {
doPlayPause: scope.doPlayPause,
// This is just for an example
callDirectiveFromController: scope.callDirectiveFromController
});
And you are now pretty much ready to call any of these methods from the controller as below,
$scope.vlcControls.callDirectiveFromController();
Check the code below and execute which is working nicely as you expected :-)
var myApp = angular.module('myApp', []);
myApp.controller('myModuleCtrl', function ($scope, $http, $controller, $compile) {
$scope.vlcControls = {};
$compile('<vlc-controls controller-ref="vlcControls"></vlc-controls>')($scope);
$scope.vlcControls.callDirectiveFromController();
});
myApp.directive('vlcControls', function ($compile, $rootScope, $timeout, $window)//, pictureboxConstants)
{
var linker = function (scope, element, attrs) {
scope.getVLC = function (name) {
if ($window.document[name]) {
return $window.document[name];
}
if ($window.navigator.appName.indexOf("Microsoft Internet") == -1) {
if ($window.document.embeds && $window.document.embeds[name])
return $window.document.embeds[name];
} else {
return $window.document.getElementById(name);
}
};
scope.doPlayPause = function (vlcPlayer, event) {
var vlc = scope.getVLC(vlcPlayer);
if (vlc) {
if (vlc.playlist.isPlaying) {
vlc.playlist.pause();
angular.element(event.target).children().removeClass('fa fa-pause font-12');
angular.element(event.target).children().addClass('fa fa-play font-12');
} else {
if (vlc.audio.mute == true) {
//do something
}
vlc.playlist.play();
}
}
};
scope.callDirectiveFromController = function() {
console.log('I called from the controller but executed inside the directive :-)');
};
scope.controllerRef = scope.controllerRef || {};
angular.extend(scope.controllerRef, {
doPlayPause: scope.doPlayPause,
// This is just for an example
callDirectiveFromController: scope.callDirectiveFromController
});
};
return {
restrict: "E",
scope: {
/* This is the reference object passed from the controller */
controllerRef: '='
},
link: linker
};
});
angular.bootstrap(document, ['myApp']);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-controller="myModuleCtrl">
</div>
Upvotes: 0
Reputation: 18647
One way is to $broadcast
an event from the controller
to directive
and to listen in directive.
You can even send the parameters in the form of an object through it.
$rootScope.$broadcast('PlayPause',{});
will be in controller
in directive,
scope.$on('PlayPause',function(event, data){
scope.doPlayPause(data.vlcPlayer, data.event)
});
Controller:
myApp.controller('MyCtrl', function($rootScope){
var that = this;
this.select = function(){
$rootScope.$broadcast('PlayPause',{vlcPlayer: 'vlcPlayer',event: 'event'});
}
})
Directive:
myApp.directive('vlcControls', function ($compile, $rootScope, $timeout, $window, pictureboxConstants) {
var linker = function (scope, element, attrs) {
scope.getVLC = function (name) {
if ($window.document[name]) {
return $window.document[name];
}
if ($window.navigator.appName.indexOf("Microsoft Internet") == -1) {
if ($window.document.embeds && $window.document.embeds[name])
return $window.document.embeds[name];
} else {
return $window.document.getElementById(name);
}
}
scope.doPlayPause = function (vlcPlayer, event) {
var vlc = scope.getVLC(vlcPlayer);
if (vlc) {
if (vlc.playlist.isPlaying) {
vlc.playlist.pause();
angular.element(event.target).children().removeClass('fa fa-pause font-12');
angular.element(event.target).children().addClass('fa fa-play font-12');
} else {
if (vlc.audio.mute == true) {
//do something
}
vlc.playlist.play();
}
}
}
scope.$on('PlayPause',function(event, data){
scope.doPlayPause(data.vlcPlayer, data.event)
});
};
return {
myApp.directive('vlcControls', function ($compile, $rootScope, $timeout, $window, pictureboxConstants) {
var linker = function (scope, element, attrs) {
scope.getVLC = function (name) {
if ($window.document[name]) {
return $window.document[name];
}
if ($window.navigator.appName.indexOf("Microsoft Internet") == -1) {
if ($window.document.embeds && $window.document.embeds[name])
return $window.document.embeds[name];
} else {
return $window.document.getElementById(name);
}
}
scope.doPlayPause = function (vlcPlayer, event) {
var vlc = scope.getVLC(vlcPlayer);
if (vlc) {
if (vlc.playlist.isPlaying) {
vlc.playlist.pause();
angular.element(event.target).children().removeClass('fa fa-pause font-12');
angular.element(event.target).children().addClass('fa fa-play font-12');
} else {
if (vlc.audio.mute == true) {
//do something
}
vlc.playlist.play();
}
}
}
scope.$on('PlayPause',function(event, data){
scope.doPlayPause(data.vlcPlayer, data.event)
});
};
return {
restrict: "E",
link: linker
};
});
The other way is to use a factory and share the method between the controller
and directive
,
Check this so post for more details
Upvotes: 0
Reputation: 2603
There are number of ways to do that, one of them is through broadcasting an event and listening to it in directive
However, I am not aware of the entire context and what exactly are you trying to achieve, but it looks like there is a small issue in a design. The question I would ask is "why would you want to call a method in a directive from parent controller?" Ideally, when you work with directive, it's functionality is self-contained and if you need to interact with outside world, then you either do it through variables binding or, as I already mentioned, events.
I am sure that there is a way to do exactly what you want, but given the information in the post, it is not necessary.
Upvotes: 0
Reputation: 13775
You should use $broadcast
and $on
to handle the communication from controller to directive.
To me, this is a code smell. If something is shared between parent and directive scope, it should be done through a binding. If you have to use the pub-sub pattern like this, you should rethink how you're using your directives, IMO.
Your directive should be able to do whatever it needs to without being called directly from the parent controller. If there's something it needs from the parent controller, it should be bound using attributes or a non-isolate scope.
Upvotes: 1