I want to dynamically add ngClick to an attribute directive.
javascript
angular.module('app')
.directive('myDirective', ['$log', function ($log) {
return {
restrict: 'A', // PAY ATTENTION TO THIS LINE
compile: function (tElement) {
tElement.attr('ng-click', 'onClick()');
return function postLink(scope) {
scope.onClick = function () {
$log.debug('myDirective is clicked');
}
}
}
}
}]);
markup
<button my-directive>Click Me</button>
From the element inspector of Chrome, I can see that the ng-click attribute is added to the button.
I expect to see the text "myDirective is clicked." in the console when the button is clicked, but actually there's nothing printed. No error is raised. Anyone can help? Thanks in advance.
Rather than using link inside compile use the link function directly as shown below
link: function(scope, element, attrs) {
element.onClick(function(){
$log.debug('myDirective is clicked');
});
}
You can directly add the click handler to the element, you need not bind ng-click directive inside your directive.
Hello please try this one,
HTML:
<div ng-app="angularApp">
<div ng-controller="dirCtrl1">
<button ng-click="clickFun('clicked')">Button</button>
<button my-directive="directive">With directive</button>
</div>
</div>
JS:
.controller('dirCtrl1', function ($scope) {
$scope.clickFun = function (msg) {
console.log(msg);
};
})
.directive('myDirective', function(){
return{
restrict: 'A',
link: function(scope, ele, attr){
var eventName = attr.evetName || 'click';
var mas = attr.myDirective || 'just console';
ele.on(eventName, function(){
console.log(mas);
});
}
};
});
Related
I have a website with tons of Formuars and I allways do the same thing before and after submitting a form. So I want to write a directive, which hide the magic which must be done.
I've the folloing markup (the ng-click is only to shorten the code. In the real code it will be hidden inside a template):
<form class="form" name="form" ng-submit="customSubmit()">
<input ... />
<my-submit ng-click="fakeSubmit()" type="button">Submit</my-submit>
</form>
The mySubmit Directive should look something like this:
module.directive('MySubmit', function ($state) {
return {
restrict: 'E',
controller: function ($scope) {
$scope.fakeSubmit = function () {
// deactivate button
var result = magicThing.callSubmitFromForm();
// activate button
// throw event, that form was submitted
return false;
}
}
};
});
In the directive controller there is the line magicThing.callSubmitFromForm(). This should trigger the ngSubmit magic with validators etc and then call the Method customSubmit(). I also want to have the result of the method customSubmit, which might be a Callback or something else.
As I mentioned above, I want to write a generic directive, so I don't know the function which I call here customSubmit()
Does anyone have in idea how to do this?
I solved the Problem myself. I just override the ngSubmit directive and use a Callback in the Submit directive. Here's the code:
module.directive('ngSubmit', function ($q) {
return {
restrict: 'A',
link: function (scope, elem, attr) {
scope.mySubmit = function (callback) {
scope.loading= true;
scope.finished= false;
$q.when(callback()).then(function () {
scope.finished= true;
}).finally(function () {
scope.loading= false;
});
};
}
};
});
module.directive('submitBtn', function ($state) {
return {
restrict: 'E',
templateUrl: 'myTemplate.html',
link: function (scope, elem, attr) {
scope.disableAfterSubmit = attr.disableAfterSubmit === 'true';
}
};
});
<form class="form" ng-submit="mySubmit(submitFkt)" ng-controller="AmnesiaPasswordCtrl">
<input ... />
</form>
<button type="submit" class="btn btn-primary" ladda="loading" ng-disabled="disable === true && finished">
Submit
</button>
I am building a custom directive somehow like this
app.directive('confirmation', function() {
return {
restrict: 'A',
scope: {
onConfirm:"&"
},
link: function (scope, element) {
$(element).confirmation(function(){
onConfirm: function(){
scope.onConfirm();
}
});
}
};
});
and use it like this
<script>
function DoSomethingOnConfirm(){
//Do Something;
}
</script>
<a confirmation on-confirm="DoSomethingOnConfirm()">Delete</a>
I don't have access to the controller so the function "DoSomethingOnConfirm()"
is a normal javascript function, how could I call this function inside the directive, I tried calling it directly but it didn't work.
From your question i understand that you wanted to call a javascript from your directive. I believe in this case you wanted to call some function when user click anchor tag directive.
Here is the code
<script>
var app = angular.module('app', []);
app.directive('confirmation', function() {
return {
restrict: 'A',
link: function (scope, element, attr) {
element.on('click',function(){
eval(attr.fname);
});
}
};
});
function DoSomethingOnConfirm(){
alert("Are you sure want to delete?");
}
function AddMe(){
alert("Added!!!");
}
</script>
<a confirmation href="javascript:;" fname="DoSomethingOnConfirm()">Delete</a>
<a confirmation href="javascript:;" fname="AddMe()">Add</a>
Instead of getting external function name from scope, i am getting it from attribute and triggering that function.
I hope this helps
I am trying to call a html page which is given in the templateUrl of my directive when I click a button, below is my code "hi" should be displayed when I click the "click me" button. Please suggest me how to do this.
sample.html:
<div ng-controller="MyController">
<button custom-click="">Click Me</button>
</div>
sample.js:
appRoot.directive('customClick', function() {
return {
link: function(scope, element, attrs) {
element.click(function(){
templateUrl:'/page.html';
});
}
}
});
Page.html:
<div><h4>HI</h4></div>
Update: The Snippet has been updated with getting the code from a URL
Adding onto the above answers:
appRoot.directive('customClick', function($http, $compile) {
return {
link: function(scope, element, attrs) {
element.click(function(){
$http.get("/page.html").then(function(resp){
$(element).html(resp.data);
var fnLink = $compile(element);
fnLink($scope);
});
});
}
}
});
P.S: Needs jQuery to run as using some functions like html() which can be bypassed if you dont want to include jQuery
I don't think that structure is possible, at all.
The easiest way would be to handle a show/hide type of functionality on the directive and have the template be there at all times.
For this you could use either ng-show, ng-hide or ng-if (and some others that I won't dig into).
base directive
appRoot.directive('customClick', function () {
return {
template: '<div><h5>HI</h5></div>',
link: function (scope, el, attrs) {
scope.active = false;
el.on('click', function () {
scope.$apply(function () {
scope.active = !scope.active;
});
});
}
}
});
ng-show
template: '<div ng-show="active"><h5>HI</h5></div>'
ng-hide
template: '<div ng-hide="!active"><h5>HI</h5></div>'
ng-if
template: '<div ng-if="active"><h5>HI</h5></div>'
Edit: If you are using templateUrl, simply put the ng-show/hide/if directive on the root element of the template being referenced, and this should work the same.
Oh, and here's a fiddle.
http://jsfiddle.net/ADukg/5426/
In the following code, i change the object's property on clicking the 'tab' element, but the corresponding ngbind span is not getting updated. Do i have to call some function to update the view?
HTML:
<html ng-app="splx">
...
<body ng-controller="Application">
<span ng-bind="obj.val"></span>
<tabpanel selector="obj">
<div tab value="junk">junk</div>
<div tab value="super">super</div>
</tabpanel>
</body>
</html>
JS:
var cf = angular.module('splx', []);
function Application($scope) {
$scope.obj = {val: "something"};
}
cf.directive('tabpanel', function() {
return {
restrict: 'AE',
scope: {
selector: '='
},
controller: ['$scope', function($scope) {}]
};
});
cf.directive('tab', function() {
return {
require: '^tabpanel',
restrict: 'AE',
scope: true,
link: function(scope, elem, attrs) {
elem.bind('click', function() {
scope.$parent.selector.val = "newthing";
});
}
};
});
cf.directive('tab', function() {
return {
require: '^tabpanel',
restrict: 'AE',
scope: true,
link: function(scope, elem, attrs) {
elem.bind('click', function() {
scope.$apply(function () {
scope.$parent.selector.val = "newthing";
});
});
}
};
});
That works for me. Just missing a little scope.$apply in there.
Might want to have a look at https://coderwall.com/p/ngisma if you find yourself using/having trouble with '$apply already in progress'.
If you want to change the value to what you clicked on, I'd do something like this:
scope.$parent.selector.val = attrs.tab;
As opposed to:
scope.$parent.selector.val = "newthing";
And then you can change your markup to look like this:
<tabpanel selector="obj">
<div tab="junk">junk</div>
<div tab="super">super</div>
</tabpanel>
Hope that helps!
First problem: you are not binding your controller to your app.
You need cf.controller('Application', Application);.
Also you need ng-controller="Application" in HTML on a parent of that span and the tabpanel directive.
Second problem: after changing that scope variable in your click event you need to
scope.$apply() to let Angular know something changed and it needs to $digest it.
You can check out my version here.
I am using bs-popover to display my contents on click(as a menu) in angularjs. But I need to hide this popover-menu when I click somewhere in the browser window. I want it to be dismissed on that type of event. How can I do that?
You need to write directive for this.
yourApp.directive('bndocumentclick',
function($document,$rootScope,$timeout) {
return {
restrict: 'EA',
link : function(scope, element, attrs) {
$document.on("click", function(ev) {
// Do stuff here to remove your popover.
}
}
}
});
HTML
<body bndocumentclick>
And
<div bs-popover ng-click="$event.stopPropagation()">
You need to use because you would not like to close your popover whenever user clicks inside popover.
The solution provied by #Jay Shukla doesn't work.
The "$event.stopPropagation()" on the element that triggers the popover doesn't stops it from closing when you make a click inside the popover.. if you have some interaction inside your popover this will be a problem.
This works:
angular.module('yourApp')
.directive('closePopovers', function ($document, $rootScope, $timeout) {
return {
restrict: 'EA',
link: function (scope, element, attrs) {
$document.on('click', function (ev) {
var targetElem = angular.element(ev.target);
if (targetElem.data('toggle') !== 'popover'
&& targetElem.parents('[data-toggle="popover"]').length === 0
&& targetElem.parents('.popover').length === 0) {
$('.popover').each(function () {
var $this = $(this);
var scope = $this.scope();
scope.$apply(function () {
scope.$hide();
});
}
);
}
});
}
};
});
On your body:
On your element that triggers the popover:
<button data-toggle="popover" [other data elements here] bs-popover>Toggle popover</button>