I successfully made a jQuery plugin into a directive.
app.directive('bxSlider', function($timeout)
{
return {
restrict: 'A',
link: function(scope, element, attrs)
{
$timeout(function(){element.bxSlider(scope.$eval(attrs.bxSlider))},1);
}
}
});
In my controller (through a click function), I'd like to call a method that is public on the plugin, but I am not sure how to do that. I tried setting the directive to a variable and calling it that way from my controller, but I get the error of ...has no method...
What is the correct way to do this?
You could broadcast an event to trigger your plugin method.
app.directive('bxSlider', function($timeout)
{
return {
restrict: 'A',
link: function(scope, element, attrs)
{
var slider;
$timeout(function() {
slider = element.bxSlider(scope.$eval(attrs.bxSlider));
}, 1);
scope.$on('reload-slider', function() {
slider.reloadSlider();
});
}
}
});
Then in the controller function you use $scope.$broadcast('reload-slider').
Related
I created a custom directive in angular. I would like to pass parent data through the directive using scope but I'm getting 'undefined' when I log scope and scope.questionId.
HTML
<a class="waves-effect waves-light btn" my-directive="" on-flag="someFunction" question-id="question">Flag</a>
Angular Directive
angular.module('myApp').directive('myDirective', function($http) {
return {
restrict: 'A',
scope: {
onFlag: '&onFlag',
questionId: '='
},
link: function(scope, element, attrs) {
element.click(function() {
console.log(scope);
console.log(scope.questionId);
return;
});
}
};
});
Try this
elem.bind:- It uses the JQLite which is lite version of JQuery. Here we are writing the code to handle the click event performed on the directive.
It is same like JQuery $("class or id").click(). (I hope this explains is sufficient)
angular.module('myApp').directive('myDirective', function($http) {
return {
restrict: 'A',
scope: {
onFlag: '&onFlag',
questionId: '='
},
link: function(scope, elem, attrs) {
elem.bind('click', function() {
console.log(scope.questionId);
});
}
};
});
I have a Problem with my AngularJS Directive named "showFileBrowser". I want to use Javascript in my Template but it will not be execute in my Browser. Here is my Code:
app.directive("showFileBrowser", function() {
return {
restrict: 'E',
template: '<script>$("#searchNote").fileTree({data: scope.filedata,sortable: false,selectable: false});</script>'
}
});
Someone know why I cant execute Javascript in a Directive or know how to do it?
You dont need to use the id, use 'element' directly.
app.directive("showFileBrowser", function() {
return {
restrict: 'E',
link: function($scope, element, attrs) {
$(element).fileTree({data: scope.filedata,sortable: false,selectable: false});
}
}
});
It works fine if I return a function, but i prefer return an Object.
app.directive("showFileBrowser", function() {
return function(scope, element, attr) {
$(element).fileTree({data: scope.filedata,sortable: false,selectable: false});
}
});
I have a controller:
function myController($scope) {
$scope.clicked = false;
}
and a directive:
function myDirective() {
return {
restrict: 'E',
link: function(scope, elem, attrs) {
elem.bind('click', function() {
// need to update controller $scope.clicked value
});
},
template: '<div>click me</div>';
replace: true;
}
}
and I´m using it like this:
<div ng-controller="myController">
<my-directive></my-directive>
</div>
How can I change the controller value of $scope.clicked ?
thanks!
As you don't use isolated scope in your directive, you can use scope.$parent.clicked to access the parent scope property.
link: function(scope, elem, attrs) {
elem.bind('click', function() {
scope.$parent.clicked = ...
});
},
I would not recommend using scope.$parent to update or access the parent scope values, you can two way bind the controller variable that needs to be updated into your directive, so your directive becomes:
function myDirective() {
return {
restrict: 'E',
scope: {
clicked: '='
},
link: function(scope, elem, attrs) {
elem.bind('click', function() {
// need to update controller $scope.clicked value
$scope.clicked = !$scope.clicked;
});
},
template: '<div>click me</div>';
replace: true;
}
}
now pass this clicked from parent:
<div ng-controller="myController as parentVm">
<my-directive clicked="parentVm.clicked"></my-directive>
</div>
function myController() {
var parentVm = this;
parentVm.clicked = false;
}
I would recommend reading up on using controllerAs syntax for your controller as that would really solidify the concept of using two way binding here.
I like to use $scope.$emit for such purposes. It allows to send data from directive to the controller.
You should create custom listener in your controller:
$scope.$on('cliked-from-directive', function(event, data){
console.log(data)
})
As you can see, now you have full access to your controller scope and you can do whatever you want. And in your directive just to use scope.$emit
link: function(scope, elem, attrs) {
elem.bind('click', function() {
scope.$emit('cliked-from-directive', {a:10})
});
Here I've created jsfiddle for you
I have a promise SharedData which return a variable service .template as well. The value is mytemplate with which I build an url that I ant to pass to templateUrl directive but without success.
app.directive('getLayout', function(SharedData) {
var buildUrl= '';
SharedData.then(function(service) {
buildUrl = service.template + '/layouts/home.html';
console.log(buildUrl); // return mytemplate/layouts/home.html which is the URL I want to use as templateUrl
});
return {
restrict: 'A',
link: function(scope, element, attrs) {...},
templateUrl: buildUrl
}
});
Thanks for helping me!
I resolve my issue using $templateRequest
app.directive('getLayout', function($templateRequest, SharedData) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
SharedData.then(function(service) {
myTemplate = $templateRequest(service.template + '/layouts/home.html');
Promise.resolve(myTemplate).then(function(value) {
element.html(value);
}, function(value) {
// not called
});
});
}
};
});
Here is a Plunker
Hope this will help some people :) and thanks to #Matthew Green
The docs seem to say that the templateUrl can be set asynchronously. However, I have not been able to show that applies to promises. So one way you can do this then while still using a promise would be to add the template to your element in the link function instead.
That would look something like this.
app.directive('getLayout', function($templateCache, SharedData) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
SharedData.then(function(templateName) {
element.html($templateCache.get(templateName));
});
}
}
});
Here is a plunkr to show a full working example. It assumes that the template is loaded into $templateCache so if it isn't you can do a $http.get() for the same effect.
Is there a way for not losing connection to the current controller when you are wrapping data with a directive ?
My problem is, that the directive within the wrapped template has no connection to the outside controller any more and so I can not execute the function.
Wrapping Directive:
myApp.directive('wrapContent', function() {
return {
restrict: "E",
scope: {
model: "=",
datas: "="
},
templateUrl: "./any/template.php",
link: function(scope, element, attr) {
// any
}
};
});
Directive within the wrapped Template
myApp.directive('doAction', function() {
return {
restrict: "A",
link: function(scope, elem, attrs) {
$(elem).click(function(e) {
scope.$apply(attrs.doAction);
});
}
}
});
Conroller:
lmsApp.controller('OutsideController', function ($scope){
$sope.sayHello = function() {
alert("hello");
};
});
HTML where I want to execute the function (template.php):
<div>
<do-action="sayHello()"></do-action>
</div>
How I call the wrapContent directive which is outside (Updated):
<div ng-controller="OutsideController">
<wrap-content model="any" datas="data_any"></wrap-content>
</div>
How can I execute the sayHello() function?
Thank you for your help! I would appreciate every answer.
wrapContent directive will be processed with the scope of controller.
DoAction directive will be processed with the isolateScope of wrapContent directive.
Solution1:
Get a reference to the sayHello function in wrapContent using '&' and execute it in event handler.
Solution2:
Instead of using scope in your event handler, use scope.$parent.
You should pass sayHallo function to your parent directive using &
myApp.directive('wrapContent', function() {
return {
restrict: "E",
scope: {
model: "=",
datas: "=",
sayHallo: "&"
},
templateUrl: "./any/template.php",
link: function(scope, element, attr) {
// any
}
};
});
HTML
<div ng-controller="OutsideController">
<wrap-content model="any" datas="data_any" sayHallo="sayHallo()"></wrap-content>
</div>
Then in your child directive, you will have sayHallo in your scope, to call it just do it this:
myApp.directive('doAction', function() {
return {
restrict: "A",
link: function(scope, elem, attrs) {
scope.sayHallo();
}
}
});
And you dont need pass it again. So your child directive should looks like this:
<div>
<do-action></do-action>
</div>
UPDATE
If you want to use all your parent model functions,without passing each function. In your child directive,just use scope.model to have access to model attributes and functions.
myApp.directive('doAction', function() {
return {
restrict: "A",
link: function(scope, elem, attrs) {
scope.model.sayHallo();
}
}
});