Why can't I use data-* as a directive's attribute name in AngularJS?

All we need is an easy explanation of the problem, so here it is.

On the this plunker you can notice a strange behavior with the attribute name’s pattern data-* in a directive.

The call :

<body ng-app="apptest" ng-controller="Controller">
  Test of data named attribute :
  <br/>
  <directivetest data-test="vartest" test="vartest" another-test="vartest"></directivetest>
</body>

of the directive :

angular.module('apptest', [])
  .controller('Controller', ['$scope',
    function($scope) {
      $scope.vartest = "This is a test";
    }
  ])
  .directive('directivetest', function() {
    return {
      restrict: 'E',
      scope: {
        dataTest: '=',
        test: '=',
        anotherTest: '='
      },
      templateUrl: "directive.html"
    }
  });

will take all the attributes of directivetest into account but data-test and therefore display :

Test of data named attribute :
Attribute with data-* name :
Attribute with regular name : This is a test
Attribute with an other regular name : This is a test

I am wondering why this happens (I wasted 4 hours before I figured out that it was the issue).

It seems to be impossible to name a directive data-*, why is that?

I read something about it here http://www.w3schools.com/tags/att_global_data.asp, is it why my attribute is undefined? It is simply not read by the browser?

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

The data- prefixed forms of directive names allow HTML validators to work because custom data attributes in HTML5 follow that form. AngularJS directive names are normalized as follows to support custom data attributes:

The normalization process is as follows:

  • Strip x- and data- from the front of the element/attributes.
  • Convert the :, -, or _-delimited name to camelCase.

Method 2

Angular automatically normalizes the attributes. Things like data-test="...", x-test="...", and test="..." are considered to be the same. You should choose one way of writing your custom attributes and stick with it; not mixing and matching.

Method 3

This is because Angular strip x- and data- from the front of the element/attributes. Thus in your case you have two attributes named test and one overwrites the other. I’ve forked your plunker as an example: Plunker

<directivetest data-foo="vartest" test="vartest" another-test="vartest"></directivetest>

scope: {
    foo: '=',
    test: '=',
    anotherTest: '='
}

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply