I am using ng-focus and ng-blur to show/hide a button. on focus of an input, a button is shown and on blur it is hidden. Show/hide is being performed using ng-show. On click of this button a function gets called.
Live Demo
Issue is that ng-blur us being called first and the button is getting hidden before the click event is fired, hence function which is to be called from that button is never getting called.
I have already fixed it by using setTimeout() but later found that it is not really a good solution. Is there any other way to fix this issue?
use ng-mouseover and ng-mouseleave
change your button to
<button ng-click="click()" ng-show="show||mouseover" ng-mouseover="mouseover=true" ng-mouseleave="mouseover=false">Click to change</button>
demo
why don't you change the $scope.show=false; in the click event of the button.
In other words, remove the blur event, and the click event will be like this.
$scope.click = function(){
alert("fuu")
$scope.text = "We changed it";
$scope.show=false;
}
I think using a bool can help you to determine the state if it's needed to hide or show the button. On mouseover of the button change the bool to determine the execution of blur function.
Try this ways :
HTML :
<div ng-app ng-controller="LoginController">
<div>{{ text }}</div>
<input ng-focus="focus()" ng-blur="blur()"></input>
<button ng-click="click()" ng-show="show==true" ng-mouseover="mouseover()">Click to change</button>
</div>
angularjs :
function LoginController($scope) {
$scope.show=false;
$scope.blurAll = true;
$scope.text = "this thing will change on click";
$scope.focus = function(){
console.log("buu");
$scope.show=true;
}
$scope.blur = function(){
if(blurAll){
console.log("baaa");
$scope.show=false;
}
}
$scope.click = function(){
alert("fuu");
$scope.text = "We changed it";
$scope.show = false;
}
$scope.mouseover = function(){
blurAll = false;
};
}
jsFiddle
use a custom directive which introduce a delay
app.directive('ngBlurDelay',['$timeout',function($timeout){
return {
scope:{
ngBlurDelay:'&'
},
link:function(scope, element, attr){
element.bind('blur',function(){
$timeout(scope.ngBlurDelay,200);
});
}
};
}])
Related
I have the option to delete an entity by clicking DELETE ENTITY. When this is clicked the words DELETE ENTITY are changed to CLICK AGAIN TO CONFIRM. I want the words to change back to DELETE ENTITY if the focus is lost on the button. I tried using ng-blur="resetConfirmDelete", but that didn't work. Any ideas?
HTML
<!--Delete entity-->
<p class="action-link no-outline" ng-click="setConfirmDelete()" ng-show="!confirmDelete" ng-if="permissions.entities.collaborator">DELETE ENTITY</p>
<p id="delete-confirm" class="action-link no-outline" ng-click="delete()" ng-show="confirmDelete" ng-if="permissions.entities.collaborator">CLICK AGAIN TO CONFIRM</p>
</div>
CONTROLLER
$scope.setConfirmDelete = function () {
$scope.confirmDelete = true;
};
$scope.resetConfirmDelete = function () {
$scope.confirmDelete = false;
}
Try using ngBlur for this: https://docs.angularjs.org/api/ng/directive/ngBlur
<p id="delete-confirm" class="action-link no-outline" ng-blur=resetConfirmDelete()">..</p>
UPD
Then you may make use of some directive that detects click anywhere outside of the specific DOM element, for example like this one:
.directive('clickElsewhere', function($parse, $rootScope) {
return {
restrict: 'A',
compile: function($element, attr) {
var fn;
fn = $parse(attr['clickElsewhere']);
return function(scope, element) {
var offEvent;
offEvent = $rootScope.$on('click', function(event, target) {
if (element.find($(target)).length || element.is($(target))) {
return;
}
return scope.$apply(function() {
return fn(scope);
});
});
return scope.$on('$destroy', offEvent);
};
}
};
});
then in the template you can do:
<p id="delete-confirm" class="action-link no-outline"
click-else-where="resetConfirmDelete()" >
You might be running into a problem using ng-blur because the statements appear to be in a div, which is not a :focus-able element by default. Try using a button instead.
Weird that ng-blur="resetConfirmDelete" didnt work, it is the right solution as much as i know.
Maybe the second <p> is not being focused when it appears there for the focuse is never lost and ng-blur is never activated.
Also try adding the ng-blur to the first <p> instead of the second one, assuming it will be focused when the second one appears.
Editted for better answer..
You need to swap the hide/show between elements and focus one at same time.
<!--Delete entity-->
<div
<p class="action-link
no-outline"
ng-click="setConfirmDelete()"
ng-show="!confirmDelete"
ng-if="permissions.facilities.collaborator">DELETE FACILITY</p>
<p id="delete-confirm"
class="action-link no-outline"
ng-click="delete()"
ng-show="confirmDelete"
ng-focus="confirmDelete"
ng-blur="blurDelete()"
ng-if="permissions.facilities.collaborator">CLICK AGAIN TO CONFIRM</p>
</div>
u'll need this lines:
ng-focus="confirmDelete"
ng-blur="blurDelete()"
With Angular, I'm trying to implement a way to change a value with an 'Edit' button click in such a way that when this button is clicked, an input is displayed over the text, and when the 'Save' button is clicked, the input's opacity becomes 0, and the model's value is applied.
I've created a jsfiddle to make my issue a bit more visual. JSFIDDLE DEMO
The issue is the following: I want to select the text to make it obvious for the user that it can be changed now, after the 'Edit' button is clicked. I do it this way:
var input = angular.element(document.querySelector('input'))[0];
input.focus();
input.select();
The only problem is that the input.select() only works on second attempt. You can see it in the demo. I have no rational explanation to this whatsoever. I need to mention that this app that I'm writing is for Electron, it means that it will only launch in Chromium, so I don't need cross-browser support for this.
When the 'Edit' button is clicked for the first time, no selection happens:
But when I click 'Save' and then 'Edit' again, everything works as expected:
Any thought would be much appreciated!
Use $timeout , it will trigger digest cycle
var app = angular.module('app', []);
app.controller('mainController', function($timeout,$scope) {
var vm = this;
vm.address = '127.0.0.1';
vm.name = 'anabelbreakfasts';
vm.editing = {
address: false
};
vm.temp = {
address: null
};
vm.changeClick = function(element) {
vm.editing[element] = !vm.editing[element];
if (vm.editing[element]) {
vm.temp[element] = vm[element];
var input = angular.element(document.querySelector('div.row.' + element + ' input'))[0];
$timeout(function(){
input.focus();
input.select();
});
} else {
vm[element] = vm.temp[element];
}
};
});
Fiddle
Use setTimeout:
setTimeout(function(){
input.select();
}, 0)
Also, input.focus() is kind of redundant
I have an angular function
$scope.show = function(el){
if($scope.steps[el] == true){
$scope.steps[el] = false;
}
else{
$scope.steps = [];
$scope.steps[el] = true;
}
}
When I call It by click this
<span class="" ng-click="show('getDate')">text</span>
Then a class 'shown' adds in this div
<div class="form-block steps second" ng-class="{shown : steps.getDate}">
but I don't get the class when call the fanction in this cod
$(document).on('click', "li", function() {
$scope.show('getDate');
console.log($scope.steps);
});
but in console i get this log
[getDate: true]
LI tag generated with JS by jquery.formstyler http://dimox.name/jquery-form-styler/ from SELECT tag
As #charlietfl stated this is happening due the fact that you updated your DOM outside of the "Angular" world. Thus, resulting of angular not knowing you did such a change.
In order to fix it you should force angular to digest by using the keyword $apply.
Example:
$(document).on('click', "li", function() {
$scope.$apply(function () {
$scope.show('getDate');
});
console.log($scope.steps);
});
Important Note: Most of the time It's poor behavior to use jQuery rather than the AngularJS way.
Thanks for #Bhojendra Nepal for noticing the bug.
I have the below html button which have onclick event
<button onclick="alert('button');" type="button">Button</button>
and the following js:
$('button').on('click', function(){
alert('jquery');
});
After executing some js code by jQuery/Javascript, i want to continue with the button onclick handler e.g: jquery alert first and than button alert.
i tried so many things like "remove attr and append it after executing my code and trigger click (it stuck in loop, we know why :) )" and "off" click. but no luck.
is it possible via jQuery/javascript?
any suggestion much appreciated
Thanks
A little bit tricky. http://jsfiddle.net/tarabyte/t4eAL/
$(function() {
var button = $('#button'),
onclick = button.attr('onclick'); //get onclick value;
onclick = new Function(onclick); //manually convert it to a function (unsafe)
button.attr('onclick', null); //clear onclick
button.click(function() { //bind your own handler
alert('jquery');
onclick.call(this); //call original function
})
});
Though there is a better way to pass params. You can use data attributes.
<button data-param="<%= paramValue %>"...
You can do it this way:
http://jsfiddle.net/8a2FE/
<button type="button" data-jspval="anything">Button</button>
$('button').on('click', function () {
var $this = $(this), //store this so we only need to get it once
dataVal = $this.data('jspval'); //get the value from the data attribute
//this bit will fire from the second click and each additional click
if ($this.hasClass('fired')) {
alert('jquery'+ dataVal);
}
//this will fire on the first click only
else {
alert('button');
$this.addClass('fired'); //this is what will add the class to stop this bit running again
}
});
Create a separate javascript function that contains what you want to do when the button is clicked (i.e. removing the onclick attribute and adding replacement code in its own function).
Then call that function at the end of
$('button').on('click', function(){
alert('jquery');
});
So you'll be left with something like this
function buttonFunction()
{
//Do stuff here
}
$('button').on('click', function()
{
alert('jquery');
buttonFunction();
});
<button type="button">Button</button>
I have a button listening for a click event , the idea is to toggle the state when the button is clicked.
The view :
<button ng-click="nextBtnClicked()" ng-disabled="{{state == 1}}" class="btn">Call</button>
The controller :
app.controller('workStation',['$scope',function($scope)
{
$scope.state = 0;
$scope.nextBtnClicked = function()
{
$scope.state = 1;
};
}]
The problem is that I don't see the changes when the button is clicked.I've also tried to execute $apply() but I got the error "Error:[$rootScope:inprog]"
You don't need to use interpolation.
Use:
ng-disabled="state == 1"
Otherwise:
ng-disabled="{{state == 1}}"
Will be evaulated into:
ng-disabled="false"
Which means the ngDisabled directive will be watching a variable named false on the associated scope.
Use
ng-click="state= !state"
This will toggle the state each time you click the button.
and
ng-disabled="state==1"
to disable the button when state is 1.