I lost a couple of hours over this. When creating a directive or attribute name in AngularJS that will be "kebab-cased," do not prefix it with data, such dataFn or dataFromApi. It becomes data-fn or data-from-api and won't work because data- is reserved by javascript for values.

Note: I'm taking a hard line, here. Such a name might work in some cases--but definitely doesn't when trying to invoke an expression passed to an isolate-scope directive.

This will work.

<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.5/angular.min.js"></script>
</head>
<body ng-app="app">
<div ng-controller="MyController as vm">
<button ng-click="vm.alert()">From Body</button>
<my-directive fn="vm.alert()"></my-directive>
</div>
</body>
</html>

<script>
angular.module('app',['MyModule']);

angular.module('MyModule', [])
.controller('MyController', MyController)
.directive('myDirective', myDirective);

function MyController(){
var vm = this;
vm.alert = function(){alert('alert');}
}

function myDirective() {
var directive = {
scope: {
fn: '&'
},
template: "<button ng-click='fn()'>From Directive</button>"
}
return directive;
}
</script>

This won't work, because data- is reserved by javascript.

<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.5/angular.min.js"></script>
</head>
<body ng-app="app">
<div ng-controller="MyController as vm">
<button ng-click="vm.alert()">From Body</button>
<!-- data-fn WILL NOT WORK -->
<my-directive data-fn="vm.alert()"></my-directive>
</div>
</body>
</html>

<script>
angular.module('app',['MyModule']);

angular.module('MyModule', [])
.controller('MyController', MyController)
.directive('myDirective', myDirective);

function MyController(){
var vm = this;
vm.alert = function(){alert('alert');}
}

function myDirective() {
var directive = {
scope: {
dataFn: '&'
},
template: "<button ng-click='dataFn()'>From Directive</button>"
}
return directive;
}
</script>

This works, using the non-reserved my- prefix.

<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.5/angular.min.js"></script>
</head>
<body ng-app="app">
<div ng-controller="MyController as vm">
<button ng-click="vm.alert()">From Body</button>
<!-- my-fn WORKS -->
<my-directive my-fn="vm.alert()"></my-directive>
</div>
</body>
</html>

<script>
angular.module('app',['MyModule']);

angular.module('MyModule', [])
.controller('MyController', MyController)
.directive('myDirective', myDirective);

function MyController(){
var vm = this;
vm.alert = function(){alert('alert');}
}

function myDirective() {
var directive = {
scope: {
myFn: '&'
},
template: "<button ng-click='myFn()'>From Directive</button>"
}
return directive;
}
</script>