jQuery Placeholder Library on AngularJS

by

This is for anyone who has to build an AngularJS application that needs to support IE9 and below. Older IE browsers do not support the input placeholder attribute. To support this functionality with older IE browsers, javascript is used. Mathias created a very useful jQuery plugin to solve this issue. You will just need to execute this statement on ready:

$('input, textarea').placeholder()

However, this may not work in certain scenarios with AngularJS due to its asynchronous nature on loading HTML templates through ng-include, directives templateUrl properties. If you crawl through the source code of the placeholder plugin, you can see the event handlers “binding” to HTML components that already exist on the page. So any HTML components that are loaded after the ready event has already triggered will not have the placeholder event handlers attached to them.

One way to go about it is to modify the jQuery plugin. But if you want to keep the plugin unchanged (where you downloaded the code through bower), another way is to create a simple AngularJS directive called ‘placeholder’.

directives.directive('placeholder', function () {
    return {
        restrict: 'A',
        scope: {
            placeholder: '@'
        },
        link: function (scope, element, attrs) {
            scope.$watch('placeholder', function () {
                if (scope.placeholder) {
                    $(element).placeholder();
                }
            });
        }
    };
});

Note: The reason for the $scope.$watch on the ‘placeholder’ attribute is due to a data bind of the String (ie. supporting localization). You may not need the scope.$watch if your placeholder attribute contains a hard-coded String.

Update (8/7/2013):
The above solution has its drawbacks if one is using the ng-model attribute on an input element due to a new isolated scope created. If you are using ng-model on your input element, then one can define a placeholder directive as:

directives.directive('placeholder', function () {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
          var placeholder = attrs.placeholder;
          if (placeholder) {
            $(element).placeholder();
          }
        }
    };
})

Note: The caveat to this solution is that the placeholder may need to be a hard-coded String. There may be a potential issue if the data in the placeholder attribute is a scope property value.

6 Comments

  1. The updated solution works nicely in my project, and with some extra code on the controller where the input is you’re still being able to use an angular ({{}}) value for the placeholder.
    I’ve got a question, which is the licensing scheme you’re providing for the code listed here in the blog?

  2. One issue I had the second code you suggested is that if you are using $http.get to get values for the ng-model (which I think is a fairly common), you’ll need to defer running the placeholder() with something like a $timeout otherwise it’ll think its all blank.

  3. I m not able to get the placeholder when the page is loaded.
    But on blur of the text field it is working.
    Can u guide how to get on load

  4. Works like a charm on IE!!!! But, the solution is somehow not working on Chrome or FF. It breaks ng-model that is on the input.

    • Hi Venkat, you’re right that this solution does not work if you are using ng-model due to scope handling. I updated my post to show an alternative solution for ng-model. Hopefully that works out for you!

Leave a Reply

Your email address will not be published. Required fields are marked *