IE input clear icon sometimes not trigger the change event - javascript

I'm using AngularJS in our project and I find IE provides a clear icon on every input box by default. But when I click the 'X' icon the change event won't be fired.
Can someone kindly help me find a simple way to solve this issue?
It worked in plnkr, it's very weird...
$scope.$watch('model.search', function(search){
console.log(search);
}, true);
http://plnkr.co/edit/U8BMJtBnyK1oxviMV9aL?p=preview
I remove all the class and analytics in the input element, it still can not trigger the change...
Thanks in advance!

I would stop worrying about it by hiding this feature-
input::-ms-clear {
display: none;
}
That is just one more of countless non-standard browser features that Microsoft introduce that contain missing functionality.
Our time is too precious. Coding specifically for IE has been a pain for a decade...

I was able to solve this using the following directive, for those looking for an alternative to hiding the clear button. It may not be perfect yet, so I welcome any feedback :)
angular
.module('yourModuleName')
.directive('input', FixIEClearButton);
FixIEClearButton.$inject = ['$timeout', '$sniffer'];
function FixIEClearButton($timeout, $sniffer) {
var directive = {
restrict: 'E',
require: '?ngModel',
link: Link,
controller: function () { }
};
return directive;
function Link(scope, elem, attr, controller) {
var type = elem[0].type;
//ie11 doesn't seem to support the input event, at least according to angular
if (type !== 'text' || !controller || $sniffer.hasEvent('input')) {
return;
}
elem.on("mouseup", function (event) {
var oldValue = elem.val();
if (oldValue == "") {
return;
}
$timeout(function () {
var newValue = elem.val();
if (newValue !== oldValue) {
elem.val(oldValue);
elem.triggerHandler('keydown');
elem.val(newValue);
elem.triggerHandler('focus');
}
}, 0, false);
});
scope.$on('$destroy', destroy);
elem.on('$destroy', destroy);
function destroy() {
elem.off('mouseup');
}
}
}

Related

clear input field content that has a directive for currency format in angularjs

This is the first time when I am using and try to learn angular and typescript, I have an input field that I want to use a currency format directive for that and I searched and found proper directive but when the user wants to delete the input number and use backspace button, after deleting input numbers, 0 will show in input and then user have to press backspace again to clear the input field, I find that $filter(number) is doing this and I use a simple code to prevent that.
here is my code
mymodule.directive("currency", function($filter) {
"use strict";
return {
require: "?ngModel",
link: function(scope, elem, attrs, ctrl) {
if (!ctrl) {
return;
}
ctrl.$formatters.unshift(function() {
return $filter("number")(ctrl.$modelValue);
});
ctrl.$parsers.unshift(function(viewValue) {
var num= viewValue.replace(/[\,\.]/g, ""),
b = $filter("number")(num);
// i add this if to check if the value is zero don't show in input
if (b == 0) {
elem.val("");
} else {
elem.val(b);
}
return num;
});
}
};
})
but I am not sure that this is a good idea.
Is there any other way to achieve what I want?

Binding to spacebar (32) keyup/down when pressed twice

I'm using Angular JS and I need to write a directive that will initiate a function ONLY when the spacebar (32) gets pressed twice in a row. The app has forms also and users might need to actually hit space twice in a textarea or input field, so we need to account for that as well. We also need to make sure the page doesn't scroll when pressing the spacebar, but doing event.preventDefault(); actually prevents the spacebar from being used to type a space in a form element. Any ideas as to how to accomplish this? Is it even possible? I might consider binding to a key combination instead if this is too difficult. Here is a sample of what I have so far:
(function() {
"use strict";
angular
.module("app.spaceFunc")
.directive("triggerFunc", triggerFunc);
triggerFunc.$inject = ["$window"];
/* #ngInject */
function triggerFunc($window) {
var directive = {
link: link,
restrict: "A"
};
return directive;
function link(scope, element, attrs) {
var upHitOnce = false;
angular.element($window).bind("keydown", function(event) {
if ((event.keycode || event.which) === 32) {
//Prevents page scrolling (spacebar default's behaviour)
event.preventDefault();
if (upHitOnce) {
//some function gets executed here
console.log("Spacebar pressed twice");
upHitOnce = false;
} else {
upHitOnce = true;
}
} else {
upHitOnce = false;
}
});
}
}
})();
The directive is attached to the body element
<body trigger-func>

angularjs ng-blur not working in Chrome or Firefox

I am using ui.bootstrap collapse directive to display drop down menu.
I would like to automatically collapse it when user clicks outside of the div.
When user clicks on Filter button I set focus using:
.directive('setFocus', function () {
return {
restrict: 'A',
scope: {
focusValue: "=setFocus"
},
link: function ($scope, $element, attrs) {
$scope.$watch("focusValue", function (currentValue, previousValue) {
if (currentValue === true && !previousValue) {
$element[0].focus();
console.log('set focus from setFocus directive');
} else if (currentValue === false && previousValue) {
$element[0].blur();
console.log('blurr from setFocus directive');
}
})
}
}
});
HTML
<div collapse="isDropDownCollapsed" class='div2' align-element-right='el1' set-focus='!isDropDownCollapsed' ng-blur="toggleMenu()">
Controller
app.controller('testCtrl', function ($scope) {
$scope.isDropDownCollapsed = true;
$scope.toggleMenu = function () {
$scope.isDropDownCollapsed = !$scope.isDropDownCollapsed;
}
});
It works in IE v11 but focus is also lost when check box is selected.
It doesn't work in Chrome v38 or Firefox v33.1.
example code
In the end I have used this approach:
https://web.archive.org/web/20161104225152/http://vadimpopa.com/onblur-like-for-a-div-in-angularjs-to-close-a-popup/

Need help getting my angular directives to work

I am converting some code to use angular directives. I am new at this..
The old code is:
$('.header .mobile-nav ').append($('.navigation').html());
$('.header .mobile-nav li').bind('click', function(e) {
var $this = $(this);
var $ulKid = $this.find('>ul');
var $ulKidA = $this.find('>a');
if ($ulKid.length === 0 && $ulKidA[0].nodeName.toLowerCase() === 'a') {
window.location.href = $ulKidA.attr('href');
}
else {
$ulKid.toggle(0, function() {
if ($(this).css('display') === 'block') {
$ulKidA.find('.icon-chevron-down').removeClass('icon-chevron-down').addClass('icon-chevron-up');
}
else {
$ulKidA.find('.icon-chevron-up').removeClass('icon-chevron-up').addClass('icon-chevron-down');
}
});
}
e.stopPropagation();
return false;
});
My attempt at creative the correct directives is as follows:
app.directive('mobilenav', function () {
return { template: $('.navigation').html() };
});
app.directive('mobileNavMenu', function () {
var directive = {
link: link,
restrict: 'A'
};
return directive;
function link(scope, element, attrs) {
var iElement = element.find('.header .mobile-nav li');
iElement.bind('click', function (e) {
var $this = $(this);
var $ulKid = $this.find('* > ul');
var $ulKidA = $this.find('* > a');
if ($ulKid.length === 0 && $ulKidA[0].nodeName.toLowerCase() === 'a') {
window.location.href = $ulKidA.attr('href');
} else {
$ulKid.toggle(0, function () {
if ($(this).css('display') === 'block') {
$ulKidA.find('.icon-chevron-down').removeClass('icon-chevron-down').addClass('icon-chevron-up');
} else {
$ulKidA.find('.icon-chevron-up').removeClass('icon-chevron-up').addClass('icon-chevron-down');
}
});
}
e.stopPropagation();
return false;
});
}
});
The "click" event is not being bound. I think it could be because it is not finding the element. Am I using the right approach? Can you help me fix my directives?
Thanks!
I think there are a few things you could be doing better with this approach. First, I don't think your directives should searching for or modifying other elements by CSS.
So first I would modify this directive to bind directly on the passed in element:
function link(scope, element, attrs) {
//var iElement = element.find('.header .mobile-nav li');
iElement.bind('click', function (e) {
...
This might mean you need to apply your directive to a different element than you were originally intending.
Next, for the section where you toggle the chevrons, I think you might want to do this differently. You could for example, set a variable in the scope, or in a service, and then create another directive that watches that variable and responds to the changes in it. Alternatively, you might be able to use ng-show/ng-hide to elements based on the change.
These questions might be helpful to you as well:
Sharing data between directives
Changing CSS from AngularJS

Angular - Event for ng-hide and ng-show

I'd like to watch my hide and show expressions on all elements in my app.
I know I can do it by wrapping the show directive with a function which just returns the argument:
<div ng-show="catchShow(myShowExpr == 42)"></div>
However, I'd like to watch all hide/shows across all inputs in my app and the above isn't good enough.
I could also overload the ngShow / ngHide directives though I'd need to reevaluate the expression.
I could also just modify the source since it's quite simple:
var ngShowDirective = ['$animator', function($animator) {
return function(scope, element, attr) {
var animate = $animator(scope, attr);
scope.$watch(attr.ngShow, function ngShowWatchAction(value) {
var fn = toBoolean(value) ? 'show' : 'hide';
animate[fn](element);
//I could add this:
element.trigger(fn);
});
};
}];
Though then I couldn't use the Google CDN...
Is there a nicer way anyone can think of to do this ?
Here's what I've come up with (CoffeeScript)
getDirective = (isHide) ->
['$animator', ($animator) ->
(scope, element, attr) ->
animate = $animator(scope, attr)
last = null
scope.$watch attr.oaShow, (value) ->
value = not value if isHide
action = if value then "show" else "hide"
if action isnt last
scope.$emit 'elementVisibility', { element, action }
animate[action] element
last = action
]
App.directive 'oaShow', getDirective(false)
App.directive 'oaHide', getDirective(true)
Converted to JavaScript:
var getDirective = function(isHide) {
return ['$animator', function($animator) {
//linker function
return function(scope, element, attr) {
var animate, last;
animate = $animator(scope, attr);
last = null;
return scope.$watch(attr.oaShow, function(value) {
var action;
if (isHide)
value = !value;
action = value ? "show" : "hide";
if (action !== last) {
scope.$emit('elementVisibility', {
element: element,
action: action
});
animate[action](element);
}
return last = action;
});
};
}];
};
App.directive('oaShow', getDirective(false));
App.directive('oaHide', getDirective(true));
Another way to approach is to $watch the attribute of ngShow - although this would need to be done within a directive (useful if you're show/hiding an already custom directive)
scope.$watch attrs.ngShow, (shown) ->
if shown
# Do something if we're displaying
else
# Do something else if we're hiding

Categories