Problem is that ng-click works on so event if cancelTicket === false it still fires ng-click. How can I stop that?
<div class="btn-block save-changes padding-10" ng-class="{'gray':cancelTicket===false,'secondary-button':cancelTicket===true}" ng-click="CancelTicket(ticketPin)" ng-disabled="cancelTicket===false" style="display: table;">
<div class="button-container padding3" ng-class="{'pointer':cancelTicket===true}">
<button-spinner promise="cancelPromise"></button-spinner>
<div style="display: inline-block !important;"> #Translator.Translate("CANCEL") </div>
</div>
</div>
Event is triggered even if the div is disabled.
You can avoid this by using lazy evaluation of expressions like isDisabled || action() so action would not be called if isDisabled is true.
In your case it will be:
ng-click="cancelTicket === false || CancelTicket(ticketPin)"
You should change DIV tag to Button Tag.
It works for me.
You can disable click events when an element with ng-click is disabled.
jQuery:
$('*[ng-click]').on('click',function(event) {
var $el = $(event.target);
if($el.attr('disabled')) {
event.stopPropagation();
}
});
Doing this on all DOM elements could produce unwanted results. Also, you will need to run the above on any new HTML updated on the DOM.
Instead, we can modify just buttons to work as expected.
Angular:
angular.module('app').directive('button',function() {
return {
restrict: 'E',
link: function(scope,el) {
var $el = angular.element(el);
$el.bind('click', function(event) {
if($el.attr('disabled')) {
event.stopImmediatePropagation();
}
});
}
}
});
I would not do the above on div elements as it would be to heavy. Instead, modify your approach so that button elements are only used for clickable interactions. You can then style them to look like other div elements.
<a class="btn btn-danger btn-xs" ng-click="vm.handleRemove(device)" ng-disabled="status === 1">Delete</a>
Change a tag to button tag then OK
<button class="btn btn-danger btn-xs" ng-click="vm.handleRemove(device)" ng-disabled="status === 1">Delete</button>
My solution has been to use an html directive with an attribute used instead of ng-click, so that
<html-tag-directive new-click="ctrl.functionToCall()" disabled="ctrl.disabled" >
and the directive defined as follow:
1) template:
<button type="button"
ng-disabled="disabled" ng-click="onClick()">
</button>
2) controller:
angular.module('module')
.directive('htmlTagDirective',function() {
return {
restrict:'E',
templateUrl:'template.html',
scope:{
disabled:'=',
click: '&'
},
link:function(scope,element){
scope.onClick = function() {
if (!(scope.disabled)) {
scope.newClick();
}
};
}
};
});
Related
I have a button which on click will save the form information.
The problem is, user instead of clicking 1's on the "Save" button clicks on it multiple times as long as it disappears on the screen. With this, I am saving same form which inturn throw duplicate exceptions.
Please help me. Thanks in advance.
<button ng-click="myFunc()">Save</button>
In above code, myFunc() is triggered with the number of times user clicks.
Use a $scope variable and ng-disabled to update the click and check for the variable,
<button ng-click="myFunc()" ng-disabled="buttonClicked"></button>
Controller
$scope.buttonClicked = true;
I think disable the button after the first click will help you to solve this issue.
That's in case you want this feature related to multiple buttons:
JS:
$scope.disabled = {};
$scope.myFunc = function(identifier) {
$scope.disabled[identifier] = 1;
...
}
HTML:
<button ng-click="myFunc(identifier)" ng-disabled="disabled.identifier"></button>
In case that you want this feature only on one button:
JS:
$scope.disabled = 0;
$scope.myFunc = function() {
$scope.disabled = 1;
...
}
HTML
<button ng-click="myFunc()" ng-disabled="disabled"></button>
You can disable your submit button after the first click to prevent duplicate entry.
For Example, you have HTML something like,
<div ng-app="mydemo" ng-controller="myController">
<button type="submit" ng-disabled="isDisabled" ng-click="myFunc()"> Submit</button>
</div>
angular.module('mydemo', [])
.controller('myController',function($scope){
$scope.isDisabled = false;
$scope.disableButton = function() {
$scope.isDisabled = true; // To disable Button
}
});
This way you can disable button. It will surely work for you. Thanks.
create a directive for this, so that it can be reused
app.directive('clickAndDisable', function() {
return {
scope: {
clickAndDisable: '&'
},
link: function(scope, iElement, iAttrs) {
iElement.bind('click', function() {
iElement.prop('disabled',true);
scope.clickAndDisable().finally(function() {
iElement.prop('disabled',false);
})
});
}
};
});
so use click-and-disable="myFunc()" rather than ng-click
Hiding the form after first click resolved this issue.
I'm totally new to angular and I try to use angular-bootstrap-datetimepicker in my project. My html code is:
<span class="input-group-btn" ng-class="{open: openedDP}">
<button type="button" class="btn btn-default btn-sm" ng-click="open()">
<i class="glyphicon glyphicon-calendar"></i>
</button>
<ul class="dropdown-menu" role="menu">
<datetimepicker ng-model="abc"
on-set-time="close(new, old)">
</datetimepicker>
</ul>
</span>
<input id="abc" ng-model="abc" class="form-control" date-time-input="DD-MM-YYYY HH:mm:SS" />
I wanted to close a calendar when user clicks anywhere outside it. I almost copy-pasted the code from ui.bootstrap. Original one is inside directive and looks like this:
var documentClickBind = function(event) {
if (scope.isOpen && event.target !== element[0]) {
scope.$apply(function() {
scope.isOpen = false;
});
}
};
scope.$watch('isOpen', function(value) {
if (value) {
scope.$broadcast('datepicker.focus');
scope.position = appendToBody ? $position.offset(element) : $position.position(element);
scope.position.top = scope.position.top + element.prop('offsetHeight');
$document.bind('click', documentClickBind);
} else {
$document.unbind('click', documentClickBind);
}
});
My version (inside controller):
var documentClickBind = function (event) {
if ($scope.openedDP) {
$scope.$apply(function () {
$scope.openedDP = false;
});
}
};
$scope.$watch('openedDP', function (value) {
if (value) {
$timeout(function() {
$document.bind('click', documentClickBind);
}, 0, false);
} else {
$document.unbind('click', documentClickBind);
}
});
I removed "element" variable because I don't have it in my controller and it seems to work, but I don't know why. Maybe it works just by chance? Why clicking inside calendar is different than clicking anywhere else? In addition I'd like to avoid creating multiple functions like this when I have multiple datepickers on a page.
The behavior you want is built-in to the bootstrap dropdown, if you have bootstrap already in your project you might consider making use of its dropdown.
If not, you could create a custom directive on the page that broadcasts a 'page-clicked' event when the user clicks on another part of the page, then each controller can listen for that event on their scope and react accordingly.
I have links in a navigation that look similar to this
<a id="navform" href="#" tabindex="-1" onclick="mojarra.ab(this,event,'action','#form','content');return false" class="active"><span>Policy</span></a>
I am checking for form changes and trying to disable the onclick event for the links when there are changes and enable them if once the user saves the form.
$(':input').on('change', function() {
formChanged = true;
});
$('nav a').on('click', function(e){
if(formChanged){
e.preventDefault();
$(this)[0].onclick = null;
}
});
I have tried preventDefault and nulling the event according to some answers I found on here, but no luck. Could someone please tell me how to fix this?
UPDATE:
Thanks to all your answers, I got some ideas and figured how to fix it:
if($('.policy-form')){
$(':input').on('change', function() {
formChanged = true;
$('nav a').each(function(){
var handler = $(this).attr('onclick');
$(this).removeAttr('onclick');
$(this).on('click',function(){
if(formChanged){
invokeDialog("warning");
formChanged = false;
$(this).attr('onclick', handler);
}
});
});
});
Plain JavaScript one-liner
Use
document.getElementById('navform').onclick = null;
This is because only the last onclick defined will run and here we override it with null.
Note that it would be way better if you would just avoid onclick in your HTML, or if you would at least modify mojarra.ab() appropriately, so that it performs any actual actions only when you desire.
Demo:
document.getElementById('one').onclick = null;
<a id="one" href="#" onclick="alert(true)">Doesn't alerts</a>
<br/>
<a id="two" href="#" onclick="alert(true)">Does alerts</a>
EDIT
Vide comment, here is an example of toggling old onclick on and off:
var button = document.getElementById('button');
var oldOnclick = button.onclick;
document.getElementById('toggle').addEventListener('click', function() {
button.onclick = button.onclick !== null ? null : oldOnclick;
})
<input id="button" type="button" onclick="alert('Test')" value="Alert"/>
<br/>
<br/>
<input id="toggle" type="button" value="Toggle above button"/>
$('nav a').on('click', function(e){
$(this).removeAttr('onclick'); // add this line to remove inline onclick
if(formChanged){
e.preventDefault();
$(this)[0].onclick = null;
}
});
You can use the .off() method:
$('nav a').off('click');
One good practive is to add an namespace to your events.
$('nav a').on('click.somenamespacehere', function(e){
});
...
$('nav a').off('click.somenamespacehere');
In this case, you can specify later which events you want to remove (with the off method)
You can't do it that way because the on('click' event and the inline one are two different events and there's no way to tell which would happen first. But, you could replace the inline handlers with your own handler like so
on('click', function(e) {
if (formChanged) {
mojarra.ab(...);
}
});
With an inline click function there are many possibilities to control the logical flow or order of executing the functions attached to the same event.
One possibility is to change the inline code so that you can define a first function and based of the result of this you may decide if execute or not the next function.
My snippet:
// assuming the inline onclick function is like:
function mojarra_ab(_this, event, _action, _form, _content) {
$('<p>Executed function: mojarra_ab</p>').appendTo('body');
}
function myNewClick() {
$('<p>Executed function: myNewClick</p>').appendTo('body');
if ($('#yesNo option:selected').val() == 'true') {
return true; // return true to execute the mojarra_ab function
}
return false; // return false if you don't need to execute the mojarra_ab function
}
$(function () {
$('nav a').attr('onclick', function(index, attr) {
return 'if (myNewClick() == true) {' + attr + '}';
});
});
<script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
Choose if to run myNewClick and then mojarra_ab: <select id="yesNo">
<option value="true" selected>True</option>
<option value="false">False</option>
</select>
<nav>
<a id="navform" href="#" tabindex="-1" onclick="mojarra_ab(this,event,'action','#form','content');return false"
class="active"><span>Policy</span></a>
</nav>
I'm using the following directive to detect when a click is made outside a div:
app.directive('clickOut', function ($window, $parse) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
var clickOutHandler = $parse(attrs.clickOut);
angular.element($window).on('click', function (event) {
if (element[0].contains(event.target)) return;
clickOutHandler(scope, {$event: event});
scope.$apply();
});
}
};
});
In this div:
<div class="panel-body" click-out="closeMyPopup()">
<div class="row clearfix">
<div class="col-md-12">
<div class="form-inline pull-right">
<button type="button" class="form-control btn" ng-click="onCancelAnnouncement()">Cancel</button>
<button type="submit" class="form-control btn" ng-click="onSaveAnnouncement()">Save</button>
</div>
</div>
</div>
</div>
It works well, when you click outside the div, the function closeMyPopup() is triggered, the issue is that the div has buttons that triggers other functions. By some reason when other function is called, (like when the buttons are clicked) the event click outside is triggered calling the closeMyPopup(), the buttons are inside the div so the event click outside should not be called. There's another directive that I can use, that has the correct behavior and not trigger the click outside when you fire another function? Or how can I workaround this?
I also use this other directive, with the same issue:
app.directive("outsideClick", ['$document', '$parse', function ($document, $parse) {
return {
link: function ($scope, $element, $attributes) {
var scopeExpression = $attributes.outsideClick,
onDocumentClick = function (event) {
var isChild = $element.find(event.target).length > 0;
if (!isChild) {
$scope.$apply(scopeExpression);
}
};
$document.on("click", onDocumentClick);
$element.on('$destroy', function () {
$document.off("click", onDocumentClick);
});
}
}
}]);
Its because the event is being propagated to Window object.
- Window
- document
- dialog
- button
In the above hierarchy, if a click event happens on the last button element, the event will be propagated to the parent element until it reaches Window and then will close your dialog.
Solution 1:
Stop event propagation in each controller function by passing the event as a parameter and calling event.stopPropagation() function:
<button type="button" class="form-control btn" ng-click="onCancelAnnouncement($event)">Cancel</button>
...
$scope.onCancelAnnouncement($event) {
$event.stopPropagation();
}
Solution 2:
Let the event be propagated and check the target element:
angular.element($window).on('click', function (event) {
var target = $(event.target);
if(target.attr("id") === "anyid") { // or target.hasClass("someclass")
// or target.closest(".some-selector")
// just ignore
} else {
// Do whatever you need
}
});
Exactly: events will be presented to every object in the nested DOM-hierarchy unless and until you stop their propagation. This, of course, is by design: JavaScript doesn't assume that "the innermost guy I can find who's listening for this event" is the only guy who might be interested in it. Everyone who says he's listening for it, who is in the position to hear it, is going to hear it, each in their turn ... unless one of them explicitly quashes further propagation, at which JS will stop looking for anyone else to send it to. (No one has to "send the event to the outer container." Instead, they only have to tell JS not to send it on.)
I have two buttons on my page:
<a class="button accessLink"
id="loginLink"
data-disabled="false"
data-href="/MyAccount/Access/Login"
title="Login">Login</a>
<a class="button accessLink"
id="registerLink"
data-disabled="false"
data-href="/MyAccount/Access/Register"
title="Register">Register</a>
How can I use jQuery to make it so that if one of the buttons is clicked and if data-disabled is set to false then it:
Sets the data-disabled of both to "true"
Calls a function called dialog like this: dialog(this).
I also don't want the click to event to work.
$('a[data-disabled]').click(function(e) {
if (!$(this).data('disabled')) {
e.preventDefault();
$(this).attr('data-disabled', 'true');
dialog(this);
}
});
This should work:
$("a.accessLink").click(function(e){
e.preventDefault();
if($(this).data("disabled") == false) {
$("a.accessLink").data("disabled", true);
dialog(this);
}
});