Skip to content

Instantly share code, notes, and snippets.

@kkurni
Last active December 25, 2015 18:09
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kkurni/7018564 to your computer and use it in GitHub Desktop.
Save kkurni/7018564 to your computer and use it in GitHub Desktop.
Angular Placeholder for IE8/9 Support which compatible with validation attribute (e.g required)
MyApp.directive('placeholder', function($timeout) {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attr, ctrl) {
//check whether it support placeholder and cache it
scope.supportsPlaceholders = scope.supportsPlaceholders || function() {
return "placeholder" in document.createElement("input");
};
if (scope.supportsPlaceholders()) {
return;
}
//this function is used to move the caret to the left
var caretTo = function(el, index) {
if (el.createTextRange) {
var range = el.createTextRange();
range.move("character", index);
range.select();
} else if (el.selectionStart != null) {
el.focus();
el.setSelectionRange(index, index);
}
};
var setPlaceholder = function () {
element.val(attr.placeholder)
};
var clearPlaceholder = function () {
element.val('');
};
element.bind('focus', function() {
//on focus, set the caret into 0 position
if (element.val() == attr.placeholder) {
caretTo(element[0], 0);
}
});
element.bind('click', function() {
//on click, set the caret into 0 position
if (element.val() == attr.placeholder) {
caretTo(element[0], 0);
}
});
element.bind('keydown', function(event) {
//disable left or right key code when there is placeholder
if (element.val() == attr.placeholder) {
if (event.keyCode == 37 || event.keyCode == 39) {
event.preventDefault();
}
}
});
element.bind('keypress', function() {
//on key press, clear the placeholder
if (element.val() == attr.placeholder) {
clearPlaceholder();
}
});
element.bind('blur', function () {
//on blur, we just set the placeholder if there is no value
if (element.val() == '') setPlaceholder();
});
//formatter is executed when the model is changed
ctrl.$formatters.unshift(function (val) {
if (!val) {
//this timeout is needed so that the validation can finish their binding before we put our placeholder value
$timeout(function(){
setPlaceholder();
return attr.placeholder;
});
}
return val;
});
}
};
});
describe('placeholder', function() {
var element, $scope, $timeout, $compile;
beforeEach(module('MyApp'));
beforeEach(angular.mock.inject(function($rootScope, _$compile_, _$timeout_) {
$scope = $rootScope.$new();
$timeout = _$timeout_;
$compile = _$compile_;
$scope.supportsPlaceholders = function() {
return false;
};
element = angular.element('<input type="text" placeholder="enter placeholder" ng-model="model" />');
$compile(element)($scope);
$scope.$digest();
$scope = element.scope();
}));
describe('$formatter', function() {
it('should set element value to placeholder if model is undefined', function() {
$timeout.flush();
expect(element.val()).toEqual('enter placeholder');
});
it('should set element value to model value if model is defined', function() {
$timeout.flush();//flush the first time out
$scope.model = 'some model';
$compile(element)($scope);
$scope.$digest();
expect(element.val()).toEqual('some model');
});
});
describe('on keypress', function() {
it('should clear element value if it is the same as a placeholder', function() {
element.triggerHandler('keypress');
expect(element.val()).toEqual('');
});
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment