angular-modal-service set focus not working - angularjs

I am using the angular modal service and I am trying to implement some keypress functionality for a smooth UX.
<button type="button" autofocus ng-click="close('Yes')" class="btn btn-primary" data-dismiss="modal">Yes</button>
The problem is that when the modal pops up, it doesn't have focus. Focus remains on the button clicked to activate the modal.
Is there some way to reset autofocus without reloading the page? Or is there some way to grab focus when the modal activates, but have it do so each time the modal opens?
I tried implementing the focus service as described in the answer to this post, but I couldn't get it to work with the modal.
Here is a plunker that demonstrates the behavior:
Plunker

Here is the working demo:
Plunker
I ended up finding this example:
Programmatically Setting Focus
It accomplishes it with a directive on whatever element you want to get focus:
app.directive('syncFocusWith', function($timeout, $rootScope) {
return {
restrict: 'A',
scope: {
focusValue: "=syncFocusWith"
},
link: function($scope, $element, attrs) {
$scope.$watch("focusValue", function(currentValue, previousValue) {
if (currentValue === true && !previousValue) {
$element[0].focus();
} else if (currentValue === false && previousValue) {
$element[0].blur();
}
})
}
}
});
Getting it to work for my modal was easy. I just added this little timeout function to the modal's controller, giving it a half a second to display the modal before trying to set the focus:
$timeout(function() {
$scope.isFocused = true;
},500)
and this attribute on the element we want to get focus:
sync-focus-with="isFocused"

Related

Ionic popover not hiding second time

I am using Ionic version "1.1.0" and angular version "1.4.3"
I am facing issues with Ionic popover, I have created ionic popover out of html template, popover is opened based on user action, i have two buttons on the popup, and in the button handler i am writing code =>$scope.popover.hide() to close the popover, It works fine for the first time, it closes, Second time again when the popup is opened its not getting closed
need your advice and wanted to know if i am missing something
and on hide method promise, i am doing the state transition, second time when we click on the popover buttons, state transition is happening but popover is not getting closed
below is the code snippet i am using
$ionicPopover.fromTemplateUrl('app/layout/eo-confirmation-popup.html', {
scope: $scope,
backdropClickToClose: false
}).then(function (popover) {
$scope.dataLossPopover = popover;
$scope.dataLossPopover.show(angular.element(document.querySelector('.popupPosition')));
});
and on click of button calling below code
$scope.dataLossPopover.hide().then(function () {
$state.go(...);
});
Thanks,
Mallik
Try something like this
$ionicPopover.fromTemplateUrl('app/layout/eo-confirmation-popup.html', {
scope: $scope,
backdropClickToClose: false
}).then(function (popover) {
$scope.dataLossPopover = popover;
});
$scope.openPopover = function(event) {
$scope.dataLossPopover.show(event)
}
$scope.closePopover = function(event) {
$scope.dataLossPopover.hide(event).then({
$state.go();
})
}
If you are opening popup on click
<button ng-click="openPopover($event)"></button>
<button ng-click="closePopover($event)"></button>

How to use a different combination of triggers for uib-popover?

The official documentation at :https://angular-ui.github.io/bootstrap/#/popover says that the following trigger combos can be passed as param to the popover-trigger attribute :
mouseenter: mouseleave
click: click
outsideClick: outsideClick
focus: blur
none
I want to use a combination of
mouseenter: outsideClick
How to achieve this without using the popover-is-open attribute?
You can't, the docs state
The outsideClick trigger will cause the popover to toggle on click, and hide when anything else is clicked.
"anything else" includes the element itself, so toggeling the element using outsideClick on or off and will interfere with the natural behavior of other triggers.
for example if state your triggers like so popover-trigger="mouseleave outsideClick"
, the trigger mouseleave will hide the popover instead of showing it if you have already clicked the element, otherwise it will just show it on leave. (plunk).
If you can hack it using popover-is-open then continue doing so, if it bothers you too much you can always request a feature.
popover-trigger="mouseenter outsideClick" for the uib-popover directive does not seem to work as one would think.
Initially, I thought it meant the following:
On mouse enter show the popover
On mouse leave hide the popover
On click keep popover open in an active state
On outside click close popover if it is in an active state
Since it does not I needed a manual approach, the following is stated in the documentation.
For any non-supported value, the trigger will be used to both show and hide the popover. Using the 'none' trigger will disable the internal trigger(s), one can then use the popover-is-open attribute exclusively to show and hide the popover.
So I created some HTML like:
<span class="glyphicon glyphicon-info-sign"
ng-class="{'text-primary' : isInfoPopoverClicked}"
ng-click="toggleInfoPopoverClicked()"
ng-mouseenter="enterInfoPopover()"
ng-mouseleave="leaveInfoPopover()"
custom-click-outside="closeInfoPopover()"
uib-popover-template="'info.html'"
popover-trigger="'none'"
popover-is-open="isInfoPopoverOpen()"
popover-placement="auto top"
popover-append-to-body="true" >
</span>
The JS in the controller:
// Toggle popover's clicked active state
$scope.toggleInfoPopoverClicked = function() {
$scope.isInfoPopoverClicked = !$scope.isInfoPopoverClicked;
};
// Close the popover, used for outside click and close action inside the template
$scope.closeInfoPopover = function() {
delete $scope.isInfoPopoverClicked;
};
// On mouse enter, show the popover
$scope.enterInfoPopover = function() {
$scope.isInfoPopoverMouseEnter = true;
};
// On mouse leave, close the popover.
// If clicked active state is false set to undefined.
// This supports when the user clicks the icon to close,
// that mouse enter does not immediately display the popover again.
$scope.leaveInfoPopover = function() {
$scope.isInfoPopoverMouseEnter = false;
if(false === $scope.isInfoPopoverClicked) {
delete $scope.isInfoPopoverClicked;
}
};
// Expression used in the popover-is-open attribute
$scope.isInfoPopoverOpen = function() {
if($scope.isInfoPopoverClicked) {
return true;
} else if(false === $scope.isInfoPopoverClicked){
return false;
}
return $scope.isInfoPopoverMouseEnter;
};
The template for the uib-popover-template I used:
<div custom-stop-event="click" class="pull-right">
<span ng-click="closeInfoPopover()" class="glyphicon glyphicon-remove"></span>
<section>{{info}}</section>
</div>
Now the trickier part was that this solution required me to create two more directives.
One to close the popover when clicking outside the element.
Another to stop the click event fired inside the pop-up. Preventing it from closing the popover.
The custom-click-outside directive:
angular.module('LSPApp').directive('customClickOutside', ['$document', function ($document) {
return {
restrict: 'A',
scope: {
clickOutside: '&customClickOutside'
},
link: function (scope, element) {
var handler = function (event) {
if (element !== event.target && !element[0].contains(event.target)) {
scope.$applyAsync(function () {
scope.clickOutside();
});
}
};
// Might not work on elements that stop events from bubbling up
$document.on('click', handler);
// Clean up event so it does not keep firing after leaving scope
scope.$on('$destroy', function() {
$document.off('click', handler);
});
}
};
}]);
The custom-stop-event directive called from the template's HTML:
angular.module('LSPApp').directive('stopEvent', function () {
return {
restrict: 'A',
link: function (scope, element, attr) {
element.on(attr.stopEvent, function (e) {
e.stopPropagation();
});
}
};
});
Hopefully, this helps someone, my final solution had all this encapsulated in it's own directive to promote reuse.

How to prevent doubleclicking on a button with angularjs?

I want to select an element in my case a button on the page in my angularcontroller and then disable it. The button looks like this:
myBtn= $element.by.buttonText('submit')
I don't want the user to click the button twice in order to avoid to post requests in the backend. When I get the code above I get an angular reference order. What is an easy way to select a button and then set the disabled property to true so the user cannot click the button twice?
You can use ng-disabled to disable your button according to a flag set in your submit function. For example:
<form ng-submit="submit()">
...
<button type="submit" ng-disabled="isSubmitting">Submit</button>
</form>
and in your controller:
$scope.submit = function() {
$scope.isSubmitting = true;
$http.post('...').finally(function() {
$scope.isSubmitting = false;
});
};
if you have many buttons on page, then its better to create a directive so that on any button which is clickable, it doesnt get pressed twice
app.directive('ngClickDisable', 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);
})
});
}
};
});
This can be used on a button as follows:
<button ng-click-disable="functionThatReturnsPromise()">Click me</button>

How can I remove :active from bootstrap button

I have a website, where I have multiple buttons. Once a button is pressed I populate a list, though my problem is that the last pressed button keeps to be looking pressed (has the :active class). I thought about using angular's $timeout to reset the button, though the removeClass function doesn't do the trick.
My view looks like this:
div(ng-controller='productButtonController')
div(ng-repeat='product in products')
div.col-md-4
button.btn.btn-block.sell-button(id='{{product._id}}' ng-click='sell()'){{product.name}}
and my controller:
app.controller('productButtonController', ['$scope', '$timeout', 'productServices', 'flash',
function($scope, $timeout, productServices, flash) {
productServices.getProducts()
.success(function(result) {
$scope.products = result.data
})
.error(showErrorMessage(flash))
$scope.sell = function() {
console.log(this.product)
that = this
$('#' + that.product._id).removeClass('active')
}
}
])
Add the angular $window service to your dependencies for the
controller
Call the blur method on the document's active element, which will be
your button.
$window.document.activeElement.blur();
See How do you clear the focus in javascript?.
This code from Justin Poehnelt's handy GIST solves this elegantly.
app.directive('blur', [function () {
return {
restrict: 'A',
link: function (scope, element) {
element.on('click', function () {
element.blur();
});
}
};
}]);
Add the blur attribute to a button/element you need blurred after click. Eg.
<button type="button" blur>Click me</button>
If you simply want to override the focus status of the bootstrap buttons you could do it with:
.btn:focus{
outline: none;
}
Then your buttons should look like:
<button class="btn btn-default">My button 1</button>
It's also important that the stylesheet which overrides the button status is loaded after the bootstrap stylesheet.
EDIT:
Sorry, but the previous step only removes the outline. The background-color of the button still remains the same.
Since bootstrap doesn't append any active classes to the clicked element as far as i know you need to change the :focus status of the button:
$('#' + that.product._id).blur();
Let me know if this works for you.

Click event gets executed even after window.confirm returns false in angular confirmation dialog

Based on the example given here I have written a directive to display a confirmation dialog in Angular when a button is clicked. The problem is even after the user clicks on the cancel button on the confirmation dialog, the ng-click action gets triggered.
This is the directive:
app.directive('ngConfirmClick',function(){
return {
link: function(scope, element, attr) {
var msg = attr.ngConfirmClick;
var clickAction = attr.ngClick;
attr.ngClick = "";
element.bind('click', function(event) {
if(window.confirm(msg)){
scope.$eval(clickAction);
}
});
}
}
});
This is the section of my index.html that has the ng-confirm-click directives:
<input class="delete" type="button" value="" ng-click="delete(item._id)"
ng-confirm-click="Are you sure you want to delete?">
I tried setting a priority of -1 for the ng-confirm-click directive and that did not help either.
When I was debugging the code on firebug, I found that window.confirm DOES return false when the user clicks on Cancel, so I am not sure why the ng-click (clickAction in the directive code above) is getting executed.
Is there a way to stop propagating the click action if window.confirm returns false?
Any help would be appreciated.

Resources