I have an isolated scope directive that is called when I click on a button, this directive passes all the scope attrs to a element.bind('click' that opens a fancybox (to show a modal), the problem am having is when fancybox opens and a link is clicked, if I put a onclick event on that anchor, it never fires, it says the function is undefined even though is right there within the directive definition. I don't get it, what is wrong??
Here is an example:
search.directive('popup', [ function () {
return {
scope: {
content: '#',
expiration: '#',
instructions: '#'
},
restrict: 'A',
controller: function($scope, $element) {
function hello() {
alert('hello richie');
}
var attr = '<a onclick="hello();" href="google.com">' + $scope.content + '</a>';
$element.bind('click', function() {
$.fancybox.open({
modal : false,
maxWidth : 800,
maxHeight : 600,
fitToView : false,
autoSize : true,
content: attr,
closeClick : false,
openEffect : 'none',
closeEffect : 'none',
helpers: {
overlay: {
locked: false
}
},
tpl : {
closeBtn : '<button type="button" class="fancybox-item fancybox-close close my-own-close">×</button>'
}
});
});
I'm not familiar with the fancybox class you're using, but I'm guessing you'll need to call $compile on your html prior to setting it as the content, otherwise it is just raw HTML and it will have no angular context. So it will be looking for a global function called hello() which doesn't exist.
Related
I am trying to create a footer directive that I can pass an array of button objects to.
here is my array...
$scope.buttons = [
{
btnLabel: "Close",
btnClass: "btn-p2 pull-left",
show: true,
disabled: false,
callback: function(){console.log('close...');},
role: ''
},
{
btnLabel: "Save",
btnClass: "btn-p1 pull-right",
show: true,
disabled: true,
callback: saveTest,
role: ''
}
];
I have most of it working the way I want but, having issue with passing the callback functions. I am seeing the buttons but when I click the callback functions are not getting called. Any ideas on how to pass the callback functions?
Thanks and regards,
dj
Because saveTest is not defined in your scope, directive doesn't have access to it. So either you have to defined them on the scope and use them there, or you can pass them as directives attributes in its own scope:
First way:
$scope.saveTest = function () {
}
And then you can use the parent scope in your directive:
app.directive('someDirective', function() {
return {
restrict: 'E'
templateUrl: "..."
}
})
By not defining the scope in directive, you are saying I want to use parent scope here.
Second way:
app.directive('someDirective', function() {
return {
restrict: 'EA',
scope: {
saveTest: '&',
close: '&'
},
templateUrl: "..."
}
})
Now that we have defined them in the directive we have to pass them from html like this:
<div some-directive save-test="saveTest" close="close"></div>
I've searched the internet long and hard and found no straight answer. My question is simple, I want to have something like this in my markup:
<div my-tooltip-template="'mytt.tpl.html'" my-tooltip-scope="myDataItem">Some text...</div>
EDIT: Where myDataItem is a scope variable which contains my data object, and with a template which might look like:
<h1>{{dataItem.title}}</h1>
<span>{{dataItem.description}}</span>
And I want to have that template compiled with the a scope which contains myDataItem as dataItem and displayed as a tooltip. As far as I could tell by experimenting with ui-bootstrap tooltip module, the way to inject html into a tooltip is by using the directive tooltip-html-unsafe but the html injected doesn't get compiled, i.e., angular expressions are not evaluated, directives are not expanded, etc.
How do I go about creating a directive for this? I want a lean result, I don't want to have to include jQuery or any other library, just AngularJS and ui-bootstrap.
Thanks a lot!
Here're the blueprints of how you could create a tooltip according to your requirements (or modify/encorporate this with ui-bootstrap's tooltip).
app.directive("myTooltipTemplate", function($compile){
var contentContainer;
return {
restrict: "A",
scope: {
myTooltipScope: "="
},
link: function(scope, element, attrs, ctrl, linker){
var templateUrl = attrs.myTooltipTemplate;
element.append("<div ng-include='\"" + templateUrl + "\"'></div>");
var toolTipScope = scope.$new(true);
angular.extend(toolTipScope, scope.myTooltipScope);
$compile(element.contents())(toolTipScope);
}
};
});
This, of course, doesn't have any of the actual tooltip functionality, like popup, placement, etc... - it just appends the compiled template to whatever the element that this directive applies to.
Plunker
Changed plunker with closer-to-tooltip behavior;
I was able to just copy and override the directive for the tooltip-html-unsafe
angular.module( 'ui.bootstrap.tooltip')
.directive( 'tooltipSpecialPopup', function () {
return {
restrict: 'EA',
replace: true,
scope: { content: '#', placement: '#', animation: '&', isOpen: '&' },
templateUrl: 'tooltip.tpl.html'
};
})
.directive( 'tooltipSpecial', [ '$tooltip', function ( $tooltip ) {
return $tooltip( 'tooltipSpecial', 'tooltip', 'mouseenter' );
}]);
I just changed the unsafe bit to special in the directive name and changed the template.
Here's a Plunker
I found this question searching for a classic tooltip implementation in AngularJS, jQuery (and other libraries) free.
I have built the following directive if anyone is searching for one:
app.directive('tooltip', function($sce, $compile) {
return {
restrict: 'A',
scope: {
content: '=tooltipContent'
},
link: function(scope, element, attributes) {
/* Attributes */
scope.displayTooltip = false;
/* Methods */
scope.updateTooltipPosition = function(top, left) {
tooltip.css({
top: top + 'px',
left: left + 'px',
});
};
scope.getSafeContent = function(content) {
return $sce.trustAsHtml(content);
};
/* Bootstrap */
var tooltip = angular.element(
'<div ng-show="displayTooltip" class="tooltip">\
<span ng-bind-html="getSafeContent(content)"></span>\
</div>'
);
angular.element(document.querySelector('body')).append(tooltip);
/* Bindings */
element.on('mouseenter', function(event) {
scope.displayTooltip = true;
scope.$digest();
});
element.on('mousemove', function(event) {
scope.updateTooltipPosition(event.clientY + 15, event.clientX + 15);
});
element.on('mouseleave', function() {
scope.displayTooltip = false;
scope.$digest();
});
/* Compile */
$compile(tooltip)(scope);
}
};
});
You can test it here: http://jsfiddle.net/m4sr9jmn/2/
Hope it will help !
Ok, so it's fairly easy to create a directive for a colorbox, as explained here:
How to use Colorbox with Angular JS
But what if you want to then bind buttons to ng-click events? Best practice would suggest that the handler function for the action (delete in my case) should be in a directive defined on the controller. My colorbox directive looks like this:
mod.directive('colorbox', function() {
return {
restrict: 'A',
scope: true,
controller: function($scope, $element){
$scope.delete = function() {
console.log('I want this code to fire');
};
},
link: function (scope, element, attrs) {
$(element).colorbox({ inline: true, title: ' ', href: "#delconfirm", className: "delgroup", width: 450, height: 200, close: "" }, function() {
});
}
};
});
My template that will be loaded into the colorbox contains an action button with an ng-click:
<button ng-click="delete()">Delete</button>
However, that doesn't work. IF I move that delete function to my parent controller instead, and remove the controller from the directive, it then works. Any ideas why?
I am trying to load a 'class' directive using ng-class. but my directive is never loaded when i do that. The directive is a multipurpose directive, and I don't want to create an isolated scope on this. it will be loaded only when required, based on ng-class conditions hence not using attribute or element directive. has anyone tried doing this and succeeded?
this directive is called using <div ng-class="someClass {{tooltip: enabled}}"></div>
here enabled is a scope variable.
app.directive('tooltip', ['$timeout', '$location', '$rootScope', function (timer, $location, $rootScope) {
return {
restrict: 'C',
transclude: true,
link: function (scope, element) {
var printContent = function () {
/* uses the content of .tooltip-content if it is a complex html tooltip,
otherwise
you can use the title attribute for plaintext tooltips
*/
var tooltipContent = $(element).find('.tooltip-content').html();
if (!tooltipContent) {
tooltipContent = $(element).attr('title');
}
$(element).tooltip({
content: tooltipContent,
items: "img, a, span, button, div",
tooltipClass: "tooltip",
position: { my: "left+30 top", at: "right top", collision: "flipfit" },
show: { effect: "fadeIn", duration: "fast" },
hide: { effect: "fadeOut", duration: "fast" },
open: function (event, ui) { $rootScope.tooltipElement = event.target; }
});
};
timer(printContent, 0);
}
};
}]);
Interesting issue. It seems that you don't want to use the ng-class directive since that doesn't recompile the content after adding the class. You'll likely want to create your own dynamic-class directive that actually recompiles when the value is true:
app.directive('dynamicClass', function($compile) {
return {
scope: {
dynamicClassWhen: '=',
dynamicClass: '='
},
link: function(scope, elt, attrs) {
scope.$watch('dynamicClassWhen', function(val) {
if (val) {
console.log(val);
elt.addClass(scope.dynamicClass);
$compile(elt)(scope);
}
});
}
};
});
You may need to modify this for the ability to remove the class and depending on if the $compile is sufficient for you or if you need to further manipulate the html, but this seems to be the right track for you. I made a fiddle with this in action.
Hope this helps!
I'm using the $dialog directive to show a dialog in my application. The dialog is opened from another directive :
angular.module('axa.directDebit.directives').directive("mandateHistoryDetail", ['$dialog', function($dialog) {
return {
restrict: 'E',
template: '<a class="btn btn-small" ng-click="openDialog()">Détail</a>',
scope: {
model: '='
},
link: function (scope, element, attrs) {
scope.openDialog = function(){
var d = $dialog.dialog({
backdrop: true,
keyboard: true,
backdropClick: true,
dialogFade: true,
templateUrl: 'app/directDebit/views/mandates.detail.history.detail.html',
controller: 'mandates.detail.history.detail.ctrl',
resolve: {
data: function () {
return scope.model;
}
}
});
d.open();
}
},
controller: 'mandates.detail.history.detail.ctrl'
}
}]);
The problem I'm having, is that from the dialog's controller, I would like to access the calling directive's scope. In particular the 'model' property in the above code.
I've tried using resolve, but the from the dialog controller I don't know how to get hold of data.
Any idea what I should change ?
In the dialog controller, you should just add it as a dependency.
You called it data so it should be -
angular.module('yourModule').controller('mandates.detail.history.detail.ctrl',
function($scope, data){
...
});
Just as a side note - I would extract the behavior of opening the $dialog to an outside view controller and not inside a directive, 'cause it looks like application logic to me and directives should aspire to be reusable.